如何使 dict 子类 json 可序列化?

How do I make a dict subclass json serializable?

我可以用 json.dumps 表示我的 Simple_Dict_SubclassList_Subclass,但不能 Custom_Dict_Subclass。当在 List_Subclass 上调用 json.dumps 时,它的 __iter__ 方法被调用,所以我推断 json.dumps 会调用字典的 items 方法。 itemsSimple_Dict_Subclass 中调用,但在 Custom_Dict_Subclass 中未调用。如何使我的 Custom_Dict_Subclass jsonSimple_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

一般来说,假设 json.dumps 会 触发字典的 items 方法。事情是这样的 已实施,但您不能依赖它。

在你的例子中,Custom_Dict_Subclass.items 永远不会被调用,因为 (key, value) 对不会添加到 dict 对象,而是添加到它的 data 属性。

要解决这个问题,您需要在 Custom_Dict_Subclass:

class Custom_Dict_Subclass(dict):
    def __init__(self):
        dict.__init__(self)
        self.data = {}
    def __setitem__(self, key, value):
        self.data[key] = value
        super().__setitem__(key, value)

对象被正确转储,当然,(key, value) 将随后 被存储两次:在 dict 对象和它的 data 属性中。

在那种情况下,最好定义一个子 class json.JSONEncoder执行翻译一个 Custom_Dict_Subclass 对象到 json 可序列化对象和 将此 class 作为关键字参数 cls of json.dumps:

import json

class Custom_Dict_Subclass:
    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 CustomDictEncoder(json.JSONEncoder):
    def default(self, obj):
        """called by json.dumps to translate an object obj to
        a json serialisable data"""
        if isinstance(obj, Custom_Dict_Subclass):
            return obj.data
        return json.JSONEncoder.default(self, obj)  

d = Custom_Dict_Subclass()
d[0] = None
print(json.dumps(d, cls=CustomDictEncoder))