将Python namedtuple序列化为json [英] Serializing a Python namedtuple to json

查看:581
本文介绍了将Python namedtuple序列化为json的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

namedtuple 序列化为带有JSON的推荐方法是什么字段名称保留了吗?

namedtuple序列化为json只会导致序列化值,并且字段名称在转换中丢失.我希望在对json大小进行更改时也保留这些字段,因此请执行以下操作:

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

上面的代码按照我的预期序列化为json,并且在我使用的其他地方(属性访问等)表现为namedtuple,除了在迭代过程中出现类似非元组的结果(这对我的用例来说很好)之外. /p>

在保留字段名称的情况下转换为json的正确方法"是什么?

解决方案

这很棘手,因为namedtuple()是一个工厂,它返回从tuple派生的新类型.一种方法是让您的类也从UserDict.DictMixin继承,但是tuple.__getitem__已经定义,并且需要一个整数来表示元素的位置,而不是其属性的名称:

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

从本质上来说,namedtuple非常适合JSON,因为它实际上是定制类型,其键名在类型定义中是固定的,不同于字典中键名是存储在实例中.这可以防止您往返"一个命名元组,例如您不能在没有其他信息的情况下将字典解码回一个命名元组,例如dict {'a': 1, '#_type': 'foobar'}中特定于应用程序的类型标记,这有点hacky.

这不是理想的方法,但是如果您只需要将命名元组编码为字典,另一种方法是扩展或修改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"}}

What is the recommended way of serializing a namedtuple to json with the field names retained?

Serializing a namedtuple to json results in only the values being serialized and the field names being lost in translation. I would like the fields also to be retained when json-ized and hence did the following:

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

The above serializes to json as I expect and behaves as namedtuple in other places I use (attribute access etc.,) except with a non-tuple like results while iterating it (which fine for my use case).

What is the "correct way" of converting to json with the field names retained?

解决方案

This is pretty tricky, since namedtuple() is a factory which returns a new type derived from tuple. One approach would be to have your class also inherit from UserDict.DictMixin, but tuple.__getitem__ is already defined and expects an integer denoting the position of the element, not the name of its attribute:

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

At its heart the namedtuple is an odd fit for JSON, since it is really a custom-built type whose key names are fixed as part of the type definition, unlike a dictionary where key names are stored inside the instance. This prevents you from "round-tripping" a namedtuple, e.g. you cannot decode a dictionary back into a namedtuple without some other a piece of information, like an app-specific type marker in the dict {'a': 1, '#_type': 'foobar'}, which is a bit hacky.

This is not ideal, but if you only need to encode namedtuples into dictionaries, another approach is to extend or modify your JSON encoder to special-case these types. Here is an example of subclassing the Python json.JSONEncoder. This tackles the problem of ensuring that nested namedtuples are properly converted to dictionaries:

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

这篇关于将Python namedtuple序列化为json的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆