使用Python> = 2.7将嵌套的namedtuple序列化为JSON

我有一个类似于CalvinKrishy的问题 Samplebias的解决方案无法使用我拥有的数据。


我正在使用Python 2.7。


数据如下:


元组

>>> a_t = namedtuple('a','f1 words')

>>> word_t = namedtuple('word','f2 value')

>>> w1 = word_t(f2=[0,1,2], value='abc')

>>> w2 = word_t(f2=[3,4], value='def')

>>> a1 = a_t(f1=[0,1,2,3,4],words=[w1, w2])

>>> a1

a(f1=[0, 1, 2, 3, 4], words=[word(f2=[0, 1, 2], value='abc'), word(f2=[3, 4], value='def')])

辞典

>>> w3 = {}

>>> w3['f2'] = [0,1,2]

>>> w3['value'] = 'abc'

>>> w4 = {}

>>> w4['f2'] = [3,4]

>>> w4['value'] = 'def'

>>> a2 = {}

>>> a2['f1'] = [0, 1, 2, 3, 4]

>>> a2['words'] = [w3,w4]

>>> a2

{'f1': [0, 1, 2, 3, 4], 'words': [{'f2': [0, 1, 2], 'value': 'abc'}, {'f2': [3, 4], 'value': 'def'}]}

如您所见,a1和a2都相同,除了一个命名为tuple,另一个是dict。


但是json.dumps是不同的:


>>> json.dumps(a1._asdict())

'{"f1": [0, 1, 2, 3, 4], "words": [[[0, 1, 2], "abc"], [[3, 4], "def"]]}'

>>> json.dumps(a2)

'{"f1": [0, 1, 2, 3, 4], "words": [{"f2": [0, 1, 2], "value": "abc"}, {"f2": [3, 4], "value": "def"}]}'

我想要a1的json格式完全像对a2所做的那样。


繁花不似锦
浏览 176回答 2
2回答

PIPIONE

问题出在使用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 objjson.dumps(namedtuple_asdict(a1))# prints '{"f1": [0, 1, 2, 3, 4], "words": [{"f2": [0, 1, 2], "value": "abc"}, {"f2": [3, 4], "value": "def"}]}'如您所见,最大的问题是嵌套结构不是 namedtuples而是可以包含它们。

DIEA

这是我使用的版本,改编自宫城先生的版本。我使用isinstancewithcollections.abc代替hasattr,然后_type在结果字典中将一个键命名为namedtuple类的名称。import collections.abcdef _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
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python