2013-03-30 4 views
22

でPythonのタプルを保持するので、私は物事のために、すべての従来の用語を知っていない可能性があります:私はまだこれにはほとんど新たなんだJSON

JSONでエンコードするとき、それはPythonのタプルを保存することは可能ですか?今すぐjson.loads(json.dumps(tuple))私にリストを返します。タプルをリストに変換したくないのですが、JSONを使いたいと思います。だから、オプションはありますか?

理由: 私は多次元配列を使用するアプリケーションを作成していますが、必ずしも同じ形状ではありません。再帰を使用して配列を調べ、エンドポイントを文字列またはintとしてキャストするいくつかのクラスメソッドがあります。私は最近、(私の再帰がどのように動作するかに基づいて)配列(Python rawks)のより深い再帰的な検索を防ぐためにタプルを使用できることに気付きました。これは、私が自分のデータ構造を深く探求する必要がないことを私が知っている状況で便利になるかもしれません。

答えて

19

あなたが高specialzedエンコーダとデコーダフック書くことができます:Pythonのリストとタプル間の原則差異は限り、あなたは考えていないとして、JSON表現とは無関係である可変性、である

import json 

class MultiDimensionalArrayEncoder(json.JSONEncoder): 
    def encode(self, obj): 
     def hint_tuples(item): 
      if isinstance(item, tuple): 
       return {'__tuple__': True, 'items': item} 
      if isinstance(item, list): 
       return [hint_tuples(e) for e in item] 
      else: 
       return item 

     return super(MultiDimensionalArrayEncoder, self).encode(hint_tuples(obj)) 

def hinted_tuple_hook(obj): 
    if '__tuple__' in obj: 
     return tuple(obj['items']) 
    else: 
     return obj 


enc = MultiDimensionalArrayEncoder() 
jsonstring = enc.encode([1, 2, (3, 4), [5, 6, (7, 8)]]) 

print jsonstring 

# [1, 2, {"items": [3, 4], "__tuple__": true}, [5, 6, {"items": [7, 8], "__tuple__": true}]] 

print json.loads(jsonstring, object_hook=hinted_tuple_hook) 

# [1, 2, (3, 4), [5, 6, (7, 8)]] 
+1

ニースです。[pymongo](https://github.com/mongodb/mongo-python-driver/blob/master/bson/json_util.py)とまったく同様です。完全にするには、 'encode'に' dict'ブランチもあるはずです。 – georg

+0

それはなぜそれが特化されている:) OPの配列は、それらにdictsを持っていないようです。 –

+0

ありがとう!コードを読むのにはちょっと時間がかかりましたが、私はそれを手に入れました。これは、マルチd配列の再帰と同じ方法です。私は今、jsonの外にフックをしています。だから、おそらく私は 'object_hook'sを読むべきです。 – mrKelley

16

いいえ、できません。 JSON形式のタプルの概念はありません(hereでは、JSONにどのような型が存在するかを簡潔に説明しています)。 Pythonのjsonモジュールは、PythonタプルをJSONリストに変換します。これは、これがタプルとJSONの最も近いものだからです。

ここでは、ユースケースの詳細を説明していませんが、タプルを含むデータ構造の文字列表現を保存する必要がある場合は、すぐに考えられる可能性があります。状況:

  1. は(慎重; pickle.loadsは、ユーザー提供の入力に使用するのは安全ではありません)を使用するpickle
  2. 独自のエンコードおよびデコード機能を作成します。
  3. json.dumpsおよびjson.loadsの代わりにreprおよびast.literal_evalを使用してください。 reprは、出力がjson.dumpsと合理的に似ていますが、reprはタプルをリストに変換しません。 ast.literal_evalは、より強力で安全なバージョンのevalで、文字列、数値、タプル、リスト、辞書、ブーリアン、およびNoneのみをデコードします。

オプション3はおそらく最も簡単で簡単な解決策です。

2

をJSONリストの内部メンバーをテキスト形式で変更します。リストをタプルに戻すだけです。カスタムオブジェクトデコーダを使用していない場合、考慮する必要がある構造化データ型はJSONオブジェクトと配列だけです。これはPythonのdictsおよびリストとして出てきます。

def tuplify(listything): 
    if isinstance(listything, list): return tuple(map(tuplify, listything)) 
    if isinstance(listything, dict): return {k:tuplify(v) for k,v in listything.items()} 
    return listything 

すると、あなたが解読を専門に、またはいくつかのJSON配列はPythonのタプルを可能にするPythonのリストや他の人になりたいしている場合は、情報を入力する注釈を付け辞書やタプルのデータ項目をラップする必要があります。これは、それ自体が、何かがリストかタプル(またはその他の反復可能な型)であるかどうかに基づく分岐よりも、アルゴリズムの制御フローに影響を与える良い方法です。

3

それはのsimplejson

import simplejson 

def _to_json(python_object) : 
    if isinstance(python_object, tuple) : 
     python_object = {'__class__': 'tuple', 
         '__value__': list(python_object)} 
    else : 
     raise TypeError(repr(python_object) + ' is not JSON serializable') 

    return python_object 

def _from_json(json_object):         
    if json_object['__class__'] == 'tuple': 
     return tuple(json_object['__value__']) 
    return json_object 


jsn = simplejson.dumps((1,2,3), 
         default=_to_json, 
         tuple_as_array=False) 

tpl = simplejson.loads(jsn, object_hook=_from_json) 
関連する問題