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

Support default serialisation for a custom class in a nested type

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

例子

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

我对d的json表示很感兴趣,所以我当然要指定遇到A的实例时如何表现。

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

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

att1 可以是任何东西:A 实例、默认类型等。

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

我环顾四周,只发现了复杂的解决方案,其中将 lambda 或 class 传递给 json.dumps(),但我不明白为什么不覆盖json 序列化器,就像重写 __str__()__repr__().

也许这是不可能的? 在这种情况下,对我来说什么是简单的解决方案?请注意,在我的实际问题中,我不仅有 class A,还有嵌套在一起的各种自定义 classes,因此覆盖默认序列化程序将是自然且更简单的解决方案。

我的一次尝试

我正在尝试遵循 encoder.py

第 160 行的建议

所以从 json.JSONEncoder 子classed A 并且我声明了方法

def default(self,obj):
    return 'valid custom json representation of A'

但这不起作用,并且引发了上述 link 的第 179 行的异常。我的代码有什么问题?

默认的 JSON 编码器(您链接到的)只知道如何处理 "easy" 诸如字典、列表、字符串和数字之类的东西。它不会尝试序列化 classes,因此没有 "special" 方法可以在 class 上实现以使其 JSON 可序列化。基本上,如果你想使用 json.dumps,你将不得不传递一些额外的东西以使其与你的自定义 classes 一起工作。

当编码器不知道如何处理对象时,它会调用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}]

请注意,每个自定义 class 现在只需要实现 to_json 方法,一切都会正确序列化(假设您在调用 [=12= 时传递自定义 default 函数]).