我有以下JSON数据:
{
"Address": {
"House_Number": 2,
"State": "MA",
"Street_Number": 13
},
"Name": "John"
}
我想将它加载到如下定义的类中:
class Address:
def __init__(self):
self.House_Number = 0
class Employee:
def __init__(self):
self.Name = ''
self.Address = Address()
如果我使用类Employee
作为object_hook
,那么它对两个对象使用相同的类(具有Name
和Address
的外部对象作为成员和内部具有成员House_Number
等的对象。)。
基本上,如果e
是加载JSON数据的对象,那么
type(e.Address)
应为Address
而不是Employee
。
有没有办法将这个JSON数据加载到维护类层次结构的Employee
类中?层次结构可以任意深入。
答案 0 :(得分:13)
您可以通过查看对象来识别对象。然后,您可以将它们映射到适当的类。
使用您的示例数据:
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}
然后,创建一个将字典转换为适当的python类的函数。
这将作为json.load
传递给object_hook
:
def class_mapper(d):
return mapping[frozenset(d.keys())](**d)
在上面,使用了frozenset
,因为json中的dict键是无序的(因此是集合),映射中的dict键需要是可散列的(因此“冻结”)。
最后,使用class_mapper
函数解析json为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
如果你的json数据有可选键,你可以创建一个更健壮的class_mapper
,虽然它可能稍慢。您还需要将默认值添加到可选的类构造函数参数中。
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))