序列化Python命名为json

什么是序列化一个namedtuple JSON与保留的字段名称的build议方式是什么?

将一个namedtuple序列化为json只会导致序列化的值和字段名称在翻译中丢失。 我希望这些字段在json化后也可以保留,因此做了以下工作:

 class foobar(namedtuple('f', 'foo, bar')): __slots__ = () def __iter__(self): yield self._asdict() 

上面的序列化为json,因为我期望和行为像我在其他地方使用(属性访问等),除了非迭代像结果而迭代它(这对我的用例罚款)的名称为tuple。

什么是保留字段名称转换为json的“正确方法”?

这是非常棘手的,因为namedtuple()是一个工厂,它返回从tuple派生的新types。 一种方法是让你的类也inheritance自UserDict.DictMixin ,但是tuple.__getitem__已经被定义,并且期望一个表示元素位置的整数,而不是它的属性名称:

 >>> f = foobar('a', 1) >>> f[0] 'a' 

namedtuple对于JSON来说非常适合,因为它是一个真正的定制types,其键名是作为types定义的一部分而被固定的 ,不像字典中键名存储在实例中。 这样可以防止“往返”一个namedtuple,例如,如果没有其他信息,例如dict {'a': 1, '#_type': 'foobar'} type中的特定于应用程序的types标记,则无法将字典解码为{'a': 1, '#_type': 'foobar'} ,这有点哈克。

这并不理想,但是如果您只需要将名称对象编码到字典中,另一种方法是将您的JSON编码器扩展或修改为这些types的特殊情况。 这是一个子类化Python json.JSONEncoder 。 这解决了确保嵌套namedtuples正确转换为字典的问题:

 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"}} 

如果它只是一个你想要序列化的名称,使用_asdict()方法将会工作(Python> = 2.7)

 >>> from collections import namedtuple >>> import json >>> FB = namedtuple("FB", ("foo", "bar")) >>> fb = FB(123, 456) >>> json.dumps(fb._asdict()) '{"foo": 123, "bar": 456}' 

它看起来像你以前可以simplejson.JSONEncoder以使其工作,但与最新的simplejson代码,不再是这种情况:您必须实际修改项目代码。 我没有看到为什么simplejson不应该支持namedtuples,所以我分叉了这个项目,添加了名为support的支持,而我现在正在等待我的分支被拉回到主项目中 。 如果您现在需要修复,只需从我的叉子上拉。

编辑 :看起来像simplejson的最新版本现在本机支持与namedtuple_as_object选项,默认为True