序列化多个 类 到 JSON

Serialize multiple classes to JSON

我有一个 class A,它存储了 B 类型变量的集合,我怎样才能正确地将 class A 序列化为 JSON?

示例:

class A:
    def __init__(self):
        self.b_collection = []
    #...

class B:
    def __init__(self):
        # ...
        pass

并将 B 的实例添加到集合中:

a = A()
a.b_collection = [B(), B(), B()]

当我尝试使用 json.dumps(a) 序列化 a 时,出现此错误:Object of type A is not JSON serializable.

有没有办法指定编码器应该如何编码 class?

类似

def __encode__(self, encoder):
    encoder.start_obj()
    encoder.add_property('name', self.value)
    encoder.add_property('age', self.age)
    encoder.end_obj()

这会 return 类似

{
   name: 'Tomer',
   age: '19'
}

您可以扩展 json.JSONEncoder 来定义如何序列化您的对象。子类的 default 方法将使用 Python 对象作为参数。您可以 return 一个(希望)可编码的新对象,或者将对象传递给父对象,希望它知道如何对对象进行编码。

例如,

class A:
    def __init__(self):
        self.b_collection = []

class B:
    def __init__(self, name, age):
        self.name = name
        self.age = age


class ABEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, A):
            return {'__A__': obj.b_collection}
        elif isinstance(obj, B):
            return {'__B__': obj.__dict__}
        return super().default(obj)


a = A()
a.b_collection.append(B("Tomer", "19"))
a.b_collection.append(B("Bob", "21"))
a.b_collection.append(B("Alice", "23"))
print(json.dumps(a, cls=ABEncoder, indent=4))

会产生

{
    "__A__": [
        {
            "__B__": {
                "name": "Tomer",
                "age": "19"
            }
        },
        {
            "__B__": {
                "name": "Bob",
                "age": "21"
            }
        },
        {
            "__B__": {
                "name": "Alice",
                "age": "23"
            }
        }
    ]
}

请注意,您可以分别处理 AB;您不必先对 B 对象进行编码,然后再 return 编码 A 的可编码形式; B 对象将在稍后对列表本身进行编码时进行编码。

额外的对象使得编写解码器更容易;如果您不想将 JSON 解码为 A 的实例,则不必使它变得如此复杂。相反,您可以定义

class ABEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, A):
            return obj.b_collection
        elif isinstance(obj, B):
            return obj.__dict__
        return super().default(obj)

得到

[
    {
        "name": "Tomer",
        "age": "19"
    },
    {
        "name": "Bob",
        "age": "21"
    },
    {
        "name": "Alice",
        "age": "23"
    }
]
    

也许数据 类 可以提供帮助:

from dataclasses import asdict, dataclass
from typing import List
import json


@dataclass
class Person:
    name: str
    age: str


@dataclass
class Group:
    persons: List[Person]


data = [
    {'name': 'Tomer', 'age': '19'},
    {'name': 'Ivan', 'age': '20'}
]
persons = [Person(**person) for person in data]

group = Group(persons=persons)
assert json.dumps(asdict(group)) == '{"persons": [{"name": "Tomer", "age": "19"}, {"name": "Ivan", "age": "20"}]}'

persons = [asdict(person) for person in group.persons]
assert persons == [{"name": "Tomer", "age": "19"}, {"name": "Ivan", "age": "20"}]
assert json.dumps(persons) == '[{"name": "Tomer", "age": "19"}, {"name": "Ivan", "age": "20"}]'