将json字符串反序列化为python中的对象

60 python json

我有以下字符串

{"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)

  • 如果这有助于任何人,在我看来,唯一正确的解决方案是图书馆.不是定制的序列化.见[jsonpickle](http://jsonpickle.github.io/) (5认同)
  • 对于具有现有成员的课程,不要像这样分配`__dict__`。如果现有成员不在json字符串中,则会丢失它们。如果必须这样做,请使用`self .__ dict __。update(otherdict)` (2认同)

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时抛出未找到密钥错误,则在使用有效负载之前不会生成任何错误.

  • 我的2美分,将`return Payload(dct ['action'],dct ['method'],dct ['data'])`替换为`return Payload(dct.get('action',None),dct.get ('method',None),dct.get('data',None))`允许某些字段为可选。 (2认同)

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方法反序列化的类.


Ner*_* Jr 8

如果要保存代码行并保留最灵活的解决方案,我们可以将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'

  • 这非常接近,但不处理嵌套的JSON.`p .__ dict__ = json.loads('{"parent":{"child":{"name":"henry"}}}')`仍然需要像dict那样访问孩子. (4认同)

Luk*_*zka 8

我以为我为解决这个“挑战”而失去了所有的头发。我遇到了以下问题:

  1. 如何反序列化嵌套对象、列表等。
  2. 我喜欢具有指定字段的构造函数
  3. 我不喜欢动态字段
  4. 我不喜欢hacky的解决方案

我发现了一个名为的库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/

希望它能节省您的时间(和头发)。


Jen*_*man 6

我更喜欢添加一些字段的检查,例如,你可以捕获错误,比如你得到无效的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)


lov*_*soa 6

在最新版本的 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)

  • 这似乎是最方便的方法。 (2认同)

Sam*_*i N 5

您可以为对象创建专门的编码器:http : //docs.python.org/2/library/json.html