我可以用json.dumps
表示my Simple_Dict_Subclass
和List_Subclass
,但不能用Custom_Dict_Subclass
。当json.dumps
在List_Subclass
上被调用时,它的__iter__
方法也被调用,所以我推断json.dumps
将调用字典的items
方法。items
在Simple_Dict_Subclass
中被调用,而不是Custom_Dict_Subclass
。如何使Custom_Dict_Subclass
json
像Simple_Dict_Subclass
一样可序列化?
import json
class Custom_Dict_Subclass(dict):
def __init__(self):
self.data = {}
def __setitem__(self, key, value):
self.data[key] = value
def __getitem__(self, key):
return self.data[key]
def __str__(self):
return str(self.data)
def items(self):
print("'Items' called from Custom_Dict_Subclass")
yield from self.data.items()
class Simple_Dict_Subclass(dict):
def __setitem__(self, key, value):
super().__setitem__(key, value)
def __getitem__(self, key):
return super().__getitem__(key)
def __str__(self):
return super().__str__()
def items(self):
print("'Items' called from Simple_Dict_Subclass")
yield from super().items()
class List_Subclass(list):
def __init__(self):
self.data = []
def __setitem__(self, index, value):
self.data[index] = value
def __getitem__(self, index):
return self.data[index]
def __str__(self):
return str(self.data)
def __iter__(self):
yield from self.data
def append(self, value):
self.data.append(value)
d = Custom_Dict_Subclass()
d[0] = None
print(d) # Works
print(json.dumps(d)) # Does't work
d = Simple_Dict_Subclass()
d[0] = None
print(d) # Works
print(json.dumps(d)) # Works
l = List_Subclass()
l.append(None)
print(l) # Works
print(json.dumps(l)) # Works
输出量:
{0: None} # Custom dict string working
{} # Custom dict json.dumps not working
{0: None} # Simple dict string working
'Items' called from Simple_Dict_Subclass
{"0": null} # Simple dict json.dumps working
[None] # List string working
[null] # List json.dumps working
2条答案
按热度按时间7y4bm7vi1#
一般来说,假设
json.dumps
将触发字典的items
方法是不安全的。这就是它是如何实现的,但你不能依赖它。在本例中,
Custom_Dict_Subclass.items
永远不会被调用,因为(键,值)对没有添加到dict
对象中,而是添加到它的data
属性中。要解决这个问题,您需要调用
Custom_Dict_Subclass
中的超级方法:对象被正确转储,但当然,(key,value)将被存储两次:在
dict
对象及其data
属性中。在这种情况下,最好定义一个
json.JSONEncoder
的子类来实现Custom_Dict_Subclass
对象到json可序列化对象的转换,并给予这个类作为json.dumps
的关键字参数cls
:szqfcxe22#
使用自定义
json.JSONEncoder
的建议解决方案是实用的,但实际上只是围绕cpython中IMHO看起来像一个bug的问题工作。你应该能够子类化dict
,对吗?但是C优化的JSON编码器似乎不知道这一点。我们找到这个代码:
PyDict_GET_SIZE
直接从不受您直接控制的原生dict
结构中读取。如果你想要一个完全自定义的存储,就像在你的Custom_Dict_Subclass
中一样,那么你似乎运气不好,至少从Python 3.12开始是这样。(顺便说一句,cpython提供的OrderedDict
子类可以正常工作,因为它通过super
使用本机存储。如果性能不是问题,您可以简单地禁用基于C的JSON编码器:
json.encoder.c_make_encoder = None
。