序列化多个 类 到 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"
}
}
]
}
请注意,您可以分别处理 A
和 B
;您不必先对 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"}]'
我有一个 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"
}
}
]
}
请注意,您可以分别处理 A
和 B
;您不必先对 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"}]'