I have a class A where it stores a collection of variables of type B, how can I serialize class A to JSON properly?
example:
class A:
def __init__(self):
self.b_collection = []
#...
class B:
def __init__(self):
# ...
pass
and add instances of B into the collection:
a = A()
a.b_collection = [B(), B(), B()]
when I try to serialize a with json.dumps(a) I get this error: Object of type A is not JSON serializable.
Is there a way to specify how to encoder should encode that class?
something like
def __encode__(self, encoder):
encoder.start_obj()
encoder.add_property('name', self.value)
encoder.add_property('age', self.age)
encoder.end_obj()
which would return something like
{
name: 'Tomer',
age: '19'
}
You can extend json.JSONEncoder to define how to serialize your objects. The default method of your subclass will take a Python object as an argument. You can return a new object that is (hopefully) encodable, or pass the object on to the parent in hopes that it knows how to encode the object.
For example,
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))
would produce
{
"__A__": [
{
"__B__": {
"name": "Tomer",
"age": "19"
}
},
{
"__B__": {
"name": "Bob",
"age": "21"
}
},
{
"__B__": {
"name": "Alice",
"age": "23"
}
}
]
}
Note that you can handle A and B separately; you don't have to first encode the B objects before returning the encodable form of A; the B objects will be encoded later when the list itself is encoded.
The extra objects make it easier to write a decoder; you don't have to make it this complicated if you don't want to be able to decode the JSON to an instance of A. Instead, you can just define
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)
to get
[
{
"name": "Tomer",
"age": "19"
},
{
"name": "Bob",
"age": "21"
},
{
"name": "Alice",
"age": "23"
}
]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With