You can identify objects by looking at their keys. You can then map them to the appropriate class.
Using your example data:
class AddressClass:
# The parameters to init needs to be the same as the json keys
def __init__(self, House_Number, Street_Number, State):
self.house_number = House_Number
self.street_number = Street_Number
self.state = State
class EmployeeClass:
# Same here
def __init__(self, Name, Address):
self.name = Name
self.address = Address
# Map keys to classes
mapping = {frozenset(('House_Number',
'Street_Number',
'State')): AddressClass,
frozenset(('Name',
'Address')): EmployeeClass}
Then, create a function that converts a dictionary to an appropriate python class.
This will be passed to json.load
as object_hook
:
def class_mapper(d):
return mapping[frozenset(d.keys())](**d)
Above, frozenset
is used because dict keys in the json are unordered (hence the set) and the dict keys in the mapping needs to be hashable (hence "frozen").
Finally, parse the json with the class_mapper
function as object_hook
:
j = '''
{
"Address": {
"House_Number": 2,
"State": "MA",
"Street_Number": 13
},
"Name": "John"
}
'''
employee = json.loads(j, object_hook=class_mapper)
print(employee.name,
employee.address.house_number,
employee.address.street_number,
employee.address.state)
# John 2 13 MA
Additions
If your json data have optional keys, you can create a more robust class_mapper
, although it may be slightly slower. You also need to add default values to the class constructor parameters that are optional.
def class_mapper(d):
for keys, cls in mapping.items():
if keys.issuperset(d.keys()):
return cls(**d)
else:
# Raise exception instead of silently returning None
raise ValueError('Unable to find a matching class for object: {!s}'.format(d))