支持嵌套类型中自定义类的默认序列化

时间:2018-03-10 12:47:50

标签: python json jsonserializer

我定义了一个类A,我在其他类,容器和嵌套类型中使用了A的对象。

实施例

a = A()
b = [a,3,'hello'
c = {'hey': b, 'huy': 3}
d = [a,b,c]

我对d的json表示感兴趣,所以当然我必须指定遇到A实例时的行为方式。

对于'A'类的对象,我想得到这个(注意我正在跳过att2,这表明我不使用a.__dict__之类的东西):

{
    class_name = 'A',
    att1 = '<value of att1>',
    att3 = '<value of att3>'
}

att1可以是任何内容:A实例,默认类型等

我希望能够调用json.dumps(d)并获得所需的输出,所以我要做的是告诉班级A当json序列化程序询问时输出什么。

我环顾四周,我只找到了一个复杂的解决方案,其中lambda或类传递给json.dumps(),我无法弄清楚为什么不重写json序列化器调用的方法,就像覆盖时一样__str__()__repr__()

也许这是不可能的? 在这种情况下,在我的案例中可能是一个简单的解决方案?请注意,在我的实际问题中,我不仅有类A,而且各种自定义类嵌套在一起,因此覆盖默认的序列化器将是自然而简单的解决方案。

我的一次尝试

我正在尝试遵循encoder.py

第160行的建议

来自A的{​​{1}}子类,我声明了方法

json.JSONEncoder

但这不起作用,并引发了上述链接的第179行的例外。我的代码出了什么问题?

1 个答案:

答案 0 :(得分:1)

默认的JSON编码器(您链接到的)只知道如何处理像dicts,列表,字符串和数字这样的“简单”事物。它没有尝试序列化类,因此没有“特殊”方法可以在类上实现,使其可以序列化。基本上,如果你想使用json.dumps,你将不得不传递额外的东西,以使它适用于你的自定义类。

当编码器不知道如何处理对象时,它会调用default方法。基于你的问题,我相信你已经发现了,但你对default方法应该去哪里感到有点困惑。这是一个可以满足你需求的例子:

import json

def default(o):
    if hasattr(o, 'to_json'):
        return o.to_json()
    raise TypeError(f'Object of type {o.__class__.__name__} is not JSON serializable')

class A(object):
    def __init__(self):
        self.data = 'stuff'
        self.other_data = 'other stuff'

    def to_json(self):
        return {'data': self.data}

a = A()
b = [a, 3, 'hello']
c = {'hey': b, 'huy': 3}
d = [a, b, c]

print(json.dumps(d, default=default))

打印出来:

[{"data": "stuff"}, [{"data": "stuff"}, 3, "hello"], {"hey": [{"data": "stuff"}, 3, "hello"], "huy": 3}]

请注意,每个自定义类现在只需要实现to_json方法,并且所有内容都会正确序列化(假设您在调用default时传递自定义json.dumps函数)。