我有以下字符串
{"action":"print","method":"onData","data":"Madan Mohan"}
Run Code Online (Sandbox Code Playgroud)
我想反序列化为类的对象
class payload
string action
string method
string data
Run Code Online (Sandbox Code Playgroud)
我使用的是python 2.6和2.7
Joh*_*ooy 107
>>> j = '{"action": "print", "method": "onData", "data": "Madan Mohan"}'
>>> import json
>>>
>>> class Payload(object):
... def __init__(self, j):
... self.__dict__ = json.loads(j)
...
>>> p = Payload(j)
>>>
>>> p.action
'print'
>>> p.method
'onData'
>>> p.data
'Madan Mohan'
Run Code Online (Sandbox Code Playgroud)
Ale*_*lex 45
详细说明萨米的答案:
来自文档:
class Payload(object):
def __init__(self, action, method, data):
self.action = action
self.method = method
self.data = data
import json
def as_payload(dct):
return Payload(dct['action'], dct['method'], dct['data'])
payload = json.loads(message, object_hook = as_payload)
Run Code Online (Sandbox Code Playgroud)
我反对
.__dict__
Run Code Online (Sandbox Code Playgroud)
解决方案是,当它完成工作并且简洁时,Payload类变得完全通用 - 它不记录其字段.
例如,如果Payload消息具有意外格式,而不是在创建Payload时抛出未找到密钥错误,则在使用有效负载之前不会生成任何错误.
Lar*_*gas 11
pydantic是一个越来越流行的 Python 3.6+ 项目库。它主要使用类型提示进行数据验证和设置管理。
使用不同类型的基本示例:
from pydantic import BaseModel
class ClassicBar(BaseModel):
count_drinks: int
is_open: bool
data = {'count_drinks': '226', 'is_open': 'False'}
cb = ClassicBar(**data)
>>> cb
ClassicBar(count_drinks=226, is_open=False)
Run Code Online (Sandbox Code Playgroud)
我喜欢这个库的原因是你可以免费获得很多好东西,比如
>>> cb.json()
'{"count_drinks": 226, "is_open": false}'
>>> cb.dict()
{'count_drinks': 226, 'is_open': False}
Run Code Online (Sandbox Code Playgroud)
Gas*_*rdP 10
如果您正在使用Python 3.6中的类型提示,您可以这样做:
def from_json(data, cls):
annotations: dict = cls.__annotations__ if hasattr(cls, '__annotations__') else None
if issubclass(cls, List):
list_type = cls.__args__[0]
instance: list = list()
for value in data:
instance.append(from_json(value, list_type))
return instance
elif issubclass(cls, Dict):
key_type = cls.__args__[0]
val_type = cls.__args__[1]
instance: dict = dict()
for key, value in data.items():
instance.update(from_json(key, key_type), from_json(value, val_type))
return instance
else:
instance : cls = cls()
for name, value in data.items():
field_type = annotations.get(name)
if inspect.isclass(field_type) and isinstance(value, (dict, tuple, list, set, frozenset)):
setattr(instance, name, from_json(value, field_type))
else:
setattr(instance, name, value)
return instance
Run Code Online (Sandbox Code Playgroud)
然后,它允许您像这样实例化类型化的对象:
class Bar:
value : int
class Foo:
x : int
bar : List[Bar]
obj : Foo = from_json(json.loads('{"x": 123, "bar":[{"value": 3}, {"value": 2}, {"value": 1}]}'), Foo)
print(obj.x)
print(obj.bar[2].value)
Run Code Online (Sandbox Code Playgroud)
这种语法虽然需要Python 3.6,但并未涵盖所有情况 - 例如,支持输入.任何...但至少它不会污染需要使用额外的init/tojson方法反序列化的类.
如果要保存代码行并保留最灵活的解决方案,我们可以将json字符串反序列化为动态对象:
p = lambda:None
p.__dict__ = json.loads('{"action": "print", "method": "onData", "data": "Madan Mohan"}')
Run Code Online (Sandbox Code Playgroud)
>>>> p.action
输出:u'print'
>>>> p.method
输出:u'onData'
我以为我为解决这个“挑战”而失去了所有的头发。我遇到了以下问题:
我发现了一个名为的库jsonpickle,它已被证明非常有用。
安装:
pip install jsonpickle
Run Code Online (Sandbox Code Playgroud)
这是将嵌套对象写入文件的代码示例:
pip install jsonpickle
Run Code Online (Sandbox Code Playgroud)
输出:
John
21
John jr.
Run Code Online (Sandbox Code Playgroud)
网站:http : //jsonpickle.github.io/
希望它能节省您的时间(和头发)。
我更喜欢添加一些字段的检查,例如,你可以捕获错误,比如你得到无效的json,或者不是你期望的json,所以我使用了namedtuples:
from collections import namedtuple
payload = namedtuple('payload', ['action', 'method', 'data'])
def deserialize_payload(json):
kwargs = dict([(field, json[field]) for field in payload._fields])
return payload(**kwargs)
Run Code Online (Sandbox Code Playgroud)
当你解析的json与你想要解析的东西不匹配时,这会给你很好的错误
>>> json = {"action":"print","method":"onData","data":"Madan Mohan"}
>>> deserialize_payload(json)
payload(action='print', method='onData', data='Madan Mohan')
>>> badjson = {"error":"404","info":"page not found"}
>>> deserialize_payload(badjson)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in deserialize_payload
KeyError: 'action'
Run Code Online (Sandbox Code Playgroud)
如果你想解析嵌套关系,例如'{"parent":{"child":{"name":"henry"}}}'
你仍然可以使用namedtuples,甚至是一个更可重用的函数
Person = namedtuple("Person", ['parent'])
Parent = namedtuple("Parent", ['child'])
Child = namedtuple('Child', ['name'])
def deserialize_json_to_namedtuple(json, namedtuple):
return namedtuple(**dict([(field, json[field]) for field in namedtuple._fields]))
def deserialize_person(json):
json['parent']['child'] = deserialize_json_to_namedtuple(json['parent']['child'], Child)
json['parent'] = deserialize_json_to_namedtuple(json['parent'], Parent)
person = deserialize_json_to_namedtuple(json, Person)
return person
Run Code Online (Sandbox Code Playgroud)
给你
>>> deserialize_person({"parent":{"child":{"name":"henry"}}})
Person(parent=Parent(child=Child(name='henry')))
>>> deserialize_person({"error":"404","info":"page not found"})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in deserialize_person
KeyError: 'parent'
Run Code Online (Sandbox Code Playgroud)
在最新版本的 python 中,您可以使用marshmallow-dataclass:
from marshmallow_dataclass import dataclass
@dataclass
class Payload
action:str
method:str
data:str
Payload.Schema().load({"action":"print","method":"onData","data":"Madan Mohan"})
Run Code Online (Sandbox Code Playgroud)