2 回答

TA貢獻1829條經驗 獲得超9個贊
問題出在使用namedtuple._asdict,而不是json.dumps。如果您一起看代碼,namedtuple(..., verbose=True)將會看到以下內容:
def _asdict(self):
'Return a new OrderedDict which maps field names to their values'
return OrderedDict(zip(self._fields, self))
實際上,只有頂層被更改為OrderedDict,所有包含的元素都保持不變。這意味著嵌套的namedtuples仍然是tuple子類,并且(正確地)進行了序列化等等。
如果可以接受對特定轉換函數的調用(如對的調用_asdict),則可以編寫自己的函數。
def namedtuple_asdict(obj):
if hasattr(obj, "_asdict"): # detect namedtuple
return OrderedDict(zip(obj._fields, (namedtuple_asdict(item) for item in obj)))
elif isinstance(obj, basestring): # iterables - strings
return obj
elif hasattr(obj, "keys"): # iterables - mapping
return OrderedDict(zip(obj.keys(), (namedtuple_asdict(item) for item in obj.values())))
elif hasattr(obj, "__iter__"): # iterables - sequence
return type(obj)((namedtuple_asdict(item) for item in obj))
else: # non-iterable cannot contain namedtuples
return obj
json.dumps(namedtuple_asdict(a1))
# prints '{"f1": [0, 1, 2, 3, 4], "words": [{"f2": [0, 1, 2], "value": "abc"}, {"f2": [3, 4], "value": "def"}]}'
如您所見,最大的問題是嵌套結構不是 namedtuples而是可以包含它們。

TA貢獻1820條經驗 獲得超3個贊
這是我使用的版本,改編自宮城先生的版本。我使用isinstancewithcollections.abc代替hasattr,然后_type在結果字典中將一個鍵命名為namedtuple類的名稱。
import collections.abc
def _nt_to_dict(obj):
recurse = lambda x: map(_nt_to_dict, x)
obj_is = lambda x: isinstance(obj, x)
if obj_is(tuple) and hasattr(obj, '_fields'): # namedtuple
fields = zip(obj._fields, recurse(obj))
class_name = obj.__class__.__name__
return dict(fields, **{'_type': class_name})
elif obj_is(collections.abc.Mapping):
return type(obj)(zip(obj.keys(), recurse(obj.values())))
elif obj_is(collections.abc.Iterable) and not obj_is(str):
return type(obj)(recurse(obj))
else:
return obj
添加回答
舉報