这非常棘手,因为这namedtuple()
是一个工厂,该工厂返回从派生的新类型tuple
。一种方法是让您的类也继承自UserDict.DictMixin
,但tuple.__getitem__
已经定义了它,并且需要一个整数来表示元素的位置,而不是其属性的名称:
>>> f = foobar('a', 1)
>>> f[0]
'a'
从本质上讲,namedtuple非常适合JSON,因为它实际上是一个自定义类型,其键名作为类型定义的一部分固定,而字典中的键名存储在实例中。这可以防止您“往返”一个命名元组,例如,在没有其他信息的情况下,您无法将字典解码回一个命名元组,例如dict中的特定于应用程序的类型标记{'a': 1, '#_type': 'foobar'}
,这有点麻烦。
这不是理想的方法,但是如果您只需要将namedtuple编码为字典,则另一种方法是将JSON编码器扩展或修改为特殊类型的这些类型。这是Python的子类化示例json.JSONEncoder
。这解决了确保嵌套的命名元组正确转换为字典的问题:
from collections import namedtuple
from json import JSONEncoder
class MyEncoder(JSONEncoder):
def _iterencode(self, obj, markers=None):
if isinstance(obj, tuple) and hasattr(obj, '_asdict'):
gen = self._iterencode_dict(obj._asdict(), markers)
else:
gen = JSONEncoder._iterencode(self, obj, markers)
for chunk in gen:
yield chunk
class foobar(namedtuple('f', 'foo, bar')):
pass
enc = MyEncoder()
for obj in (foobar('a', 1), ('a', 1), {'outer': foobar('x', 'y')}):
print enc.encode(obj)
{"foo": "a", "bar": 1}
["a", 1]
{"outer": {"foo": "x", "bar": "y"}}