2013-03-30 37 views
22

我還是有點新本,所以我可能不知道所有的事情傳統術語:保留Python的元組JSON

是否有可能保持Python的元組JSON編碼時?現在json.loads(json.dumps(tuple))給了我一個名單。我不想將我的元組轉換爲列表,但我想使用JSON。那麼,有選擇嗎?

原因: 我正在創建一個使用多維數組的應用程序,並不總是相同的形狀。我有一些使用遞歸來探測數組並將端點轉換爲字符串或int的類方法。我最近意識到(根據我的遞歸如何工作),我可以使用元組來防止對數組進行更深入的遞歸搜索(Python rawks)。如果我知道我確實不需要深入探究數據結構,那麼這可以派上用場。

回答

19

您可以編寫一個高度specialzed編碼器和解碼鉤:你不是打算

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的陣列似乎沒有字跡。 –

+0

謝謝!我花了一分鐘閱讀代碼,但我明白了,這正是我需要的。這與我在多維數組上進行遞歸的方式是一樣的。我現在正在做「json之外」的鉤子,所以也許我應該閱讀'object_hook's。 – mrKelley

16

不,不可能。沒有關於JSON格式的元組的概念(請參閱here瞭解JSON中存在的類型的簡明分類)。 Python的json模塊將Python元組轉換爲JSON列表,因爲這是JSON最接近元組的元素。

在這裏你沒有給出你的用例的很多細節,但是如果你需要存儲包含元組的數據結構的字符串表示,立刻會想到一些可能性,根據你的需要可能會或可能不適合情況:

  1. 創建自己的編碼和解碼功能
  2. 使用pickle(小心; pickle.loads是不安全的用戶提供的輸入使用)。使用reprast.literal_eval代替json.dumpsjson.loadsrepr會使您的輸出在外觀上與json.dumps相似,但repr不會將元組轉換爲列表。 ast.literal_evaleval的一個不太強大,更安全的版本,它只能解碼字符串,數字,元組,列表,字典,布爾值和None

選項3可能是最簡單和最簡單的解決方案。

2

蟒蛇列表和元組之間的主要區別是可變性,這是不相干的JSON表示,只要以文本形式修改JSON列表的內部成員。只要把你回來的列表變成元組。如果您沒有使用任何自定義對象解碼器,則必須考慮的唯一結構化數據類型是JSON對象和數組,它們以python字典和列表形式出現。

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列表和其他人是蟒蛇元組,你需要在註釋類型信息的字典或元組包的數據項。這本身就是一種更好的方法來影響算法的控制流程,而不是基於某個列表或元組(或其他可迭代類型)的分支。

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)