Reputation: 163
I'm attempting to model this JSON describing a Car :
{
colour : "green"
specs : {
brakes : "good brakes"
}
}
A car 'has a' relationship with specs. Here is how I implement:
import json
class Car :
def __init__(self , colour, specs):
self.colour = colour
self.specs = specs
class Specs :
def __init__(self , brakes):
self.brakes = brakes
specs = Specs("good brakes")
car = Car("Green" , specs)
print(json.dumps(car.__dict__))
which returns:
TypeError: Object of type Specs is not JSON serializable
In order to model the "has a" relationship should I create my own to_json function in Car
?
Upvotes: 0
Views: 54
Reputation: 3338
A modification of your method to check to see if sub-object have dicts will work in this, and other simple cases. For example:
def to_dict(obj):
"""Convert objects with a '__dict__' method into nested dicts."""
return {
key: to_dict(value) if hasattr(value, '__dict__') else value
for key, value in obj.__dict__.items()
}
print(json.dumps(to_dict(car)))
There are many cases where this will fall down though:
__slots__
in your objectYou could extend the method to try and account for each of these, but it might be time to bite the bullet and either use a serialisation library (as suggested elsewhere), or write your own object specific to_dict()
methods as you suggested.
Upvotes: 1
Reputation: 1086
You should consider having an encoder class for your Car class like below
In [8]: import json
...:
...: class Car :
...: def __init__(self , colour, specs):
...: self.colour = colour
...: self.specs = specs
...:
...: class Specs :
...: def __init__(self , brakes):
...: self.brakes = brakes
...:
...:
...: specs = Specs("good brakes")
...: car = Car("Green" , specs)
...:
In [9]:
In [10]: from json import JSONEncoder
...:
In [11]: class CarEncoder(JSONEncoder):
...: def default(self, o):
...: op = o.__dict__
...: op['specs'] = o.specs.__dict__
...: return op
...:
...:
...:
In [12]: json.dumps(car, cls=CarEncoder)
Out[12]: '{"colour": "Green", "specs": {"brakes": "good brakes"}}'
In [13]:
The CarEncoder's default method will be called by json.dumps. There i have replaced specs with the dictionary of specs..
Upvotes: 1