我想将JSON数据转换为Python对象。
我从Facebook API收到JSON数据对象,我想将其存储在数据库中。
我的当前视图在Django (Python)(请求。POST包含JSON):
response = request.POST
user = FbApiUser(user_id = response['id'])
user.name = response['name']
user.username = response['username']
user.save()
这很好,但是如何处理复杂的JSON数据对象呢?
如果我能以某种方式将这个JSON对象转换为易于使用的Python对象,是不是会更好?
因此,我正在寻找一种不需要大量自定义反序列化代码就能解组任意类型(想想数据类的字典,或者数据类数组的字典的字典)的方法。
这是我的方法:
import json
from dataclasses import dataclass, make_dataclass
from dataclasses_json import DataClassJsonMixin, dataclass_json
@dataclass_json
@dataclass
class Person:
name: str
def unmarshal_json(data, t):
Unmarhsal = make_dataclass('Unmarhsal', [('res', t)],
bases=(DataClassJsonMixin,))
d = json.loads(data)
out = Unmarhsal.from_dict({"res": d})
return out.res
unmarshalled = unmarshal_json('{"1": {"name": "john"} }', dict[str, Person])
print(unmarshalled)
打印:{'1':Person(name='john')}
这里给出的答案没有返回正确的对象类型,因此我在下面创建了这些方法。如果你试图向给定JSON中不存在的类中添加更多字段,它们也会失败:
def dict_to_class(class_name: Any, dictionary: dict) -> Any:
instance = class_name()
for key in dictionary.keys():
setattr(instance, key, dictionary[key])
return instance
def json_to_class(class_name: Any, json_string: str) -> Any:
dict_object = json.loads(json_string)
return dict_to_class(class_name, dict_object)
你可以试试这个:
class User(object):
def __init__(self, name, username):
self.name = name
self.username = username
import json
j = json.loads(your_json)
u = User(**j)
只需创建一个新对象,并将参数作为映射传递。
你也可以有一个带有对象的JSON:
import json
class Address(object):
def __init__(self, street, number):
self.street = street
self.number = number
def __str__(self):
return "{0} {1}".format(self.street, self.number)
class User(object):
def __init__(self, name, address):
self.name = name
self.address = Address(**address)
def __str__(self):
return "{0} ,{1}".format(self.name, self.address)
if __name__ == '__main__':
js = '''{"name":"Cristian", "address":{"street":"Sesame","number":122}}'''
j = json.loads(js)
print(j)
u = User(**j)
print(u)
这似乎是一个XY问题(问A实际问题在哪里B)。
问题的根源是:如何有效地引用/修改深嵌套的JSON结构,而不必做obj['foo']['bar'][42]['quux'],这带来了键入挑战,代码膨胀问题,可读性问题和错误捕获问题?
使用抢
from glom import glom
# Basic deep get
data = {'a': {'b': {'c': 'd'}}}
print(glom(data, 'a.b.c'))
它还将处理列表项:
我已经对一个简单的实现进行了基准测试:
def extract(J, levels):
# Twice as fast as using glom
for level in levels.split('.'):
J = J[int(level) if level.isnumeric() else level]
return J
... 并且在复杂的JSON对象上返回0.14ms,而朴素的impl则返回0.06ms。
它还可以处理复杂的查询,例如取出所有foo.bar.记录,其中.name == 'Joe Bloggs'
编辑:
另一种性能方法是递归地使用覆盖__getitem__和__getattr__的类:
class Ob:
def __init__(self, J):
self.J = J
def __getitem__(self, index):
return Ob(self.J[index])
def __getattr__(self, attr):
value = self.J.get(attr, None)
return Ob(value) if type(value) in (list, dict) else value
现在你可以做:
ob = Ob(J)
# if you're fetching a final raw value (not list/dict
ob.foo.bar[42].quux.leaf
# for intermediate values
ob.foo.bar[42].quux.J
这一基准测试也出奇地好。与我之前的天真冲动相当。如果有人能找到一种方法来整理非叶查询的访问,请留下评论!
你可以使用
x = Map(json.loads(response))
x.__class__ = MyClass
在哪里
class Map(dict):
def __init__(self, *args, **kwargs):
super(Map, self).__init__(*args, **kwargs)
for arg in args:
if isinstance(arg, dict):
for k, v in arg.iteritems():
self[k] = v
if isinstance(v, dict):
self[k] = Map(v)
if kwargs:
# for python 3 use kwargs.items()
for k, v in kwargs.iteritems():
self[k] = v
if isinstance(v, dict):
self[k] = Map(v)
def __getattr__(self, attr):
return self.get(attr)
def __setattr__(self, key, value):
self.__setitem__(key, value)
def __setitem__(self, key, value):
super(Map, self).__setitem__(key, value)
self.__dict__.update({key: value})
def __delattr__(self, item):
self.__delitem__(item)
def __delitem__(self, key):
super(Map, self).__delitem__(key)
del self.__dict__[key]
对于通用的、经得起未来考验的解决方案。
使用python 3.7,我发现下面的代码非常简单有效。在本例中,将JSON从文件加载到字典中:
class Characteristic:
def __init__(self, characteristicName, characteristicUUID):
self.characteristicName = characteristicName
self.characteristicUUID = characteristicUUID
class Service:
def __init__(self, serviceName, serviceUUID, characteristics):
self.serviceName = serviceName
self.serviceUUID = serviceUUID
self.characteristics = characteristics
class Definitions:
def __init__(self, services):
self.services = []
for service in services:
self.services.append(Service(**service))
def main():
parser = argparse.ArgumentParser(
prog="BLEStructureGenerator",
description="Taking in a JSON input file which lists all of the services, "
"characteristics and encoded properties. The encoding takes in "
"another optional template services and/or characteristics "
"file where the JSON file contents are applied to the templates.",
epilog="Copyright Brown & Watson International"
)
parser.add_argument('definitionfile',
type=argparse.FileType('r', encoding='UTF-8'),
help="JSON file which contains the list of characteristics and "
"services in the required format")
parser.add_argument('-s', '--services',
type=argparse.FileType('r', encoding='UTF-8'),
help="Services template file to be used for each service in the "
"JSON file list")
parser.add_argument('-c', '--characteristics',
type=argparse.FileType('r', encoding='UTF-8'),
help="Characteristics template file to be used for each service in the "
"JSON file list")
args = parser.parse_args()
definition_dict = json.load(args.definitionfile)
definitions = Definitions(**definition_dict)