Вы можете расширить json.JSONEncoder
, чтобы определить, как сериализовать ваши объекты. Метод default
вашего подкласса примет в качестве аргумента объект Python. Вы можете вернуть новый объект, который (надеюсь) кодируемый, или передать объект родительскому объекту в надежде, что он знает, как кодировать объект.
Например,
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
перед возвратом кодируемой формы 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"
}
]