支持嵌套类型中自定义 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
函数]).
我定义了一个 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
函数]).