如何将JSON数据转换为Python对象

Sai*_*hna 242 python django json

我想使用Python将JSON数据转换为Python对象.

我从Facebook API接收JSON数据对象,我想将其存储在我的数据库中.

我目前在Django中查看(Python)(request.POST包含JSON):

response = request.POST
user = FbApiUser(user_id = response['id'])
user.name = response['name']
user.username = response['username']
user.save()
Run Code Online (Sandbox Code Playgroud)
  • 这工作正常,但我如何处理复杂的JSON数据对象?

  • 如果我能以某种方式将这个JSON对象转换为Python对象以便于使用,那会不会更好?

DS.*_*DS. 315

你可以在一行中使用namedtupleobject_hook:

import json
from collections import namedtuple

data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'

# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(data, object_hook=lambda d: namedtuple('X', d.keys())(*d.values()))
print x.name, x.hometown.name, x.hometown.id
Run Code Online (Sandbox Code Playgroud)

或者,轻松地重复使用:

def _json_object_hook(d): return namedtuple('X', d.keys())(*d.values())
def json2obj(data): return json.loads(data, object_hook=_json_object_hook)

x = json2obj(data)
Run Code Online (Sandbox Code Playgroud)

如果你希望它处理的是不好的属性名称键,检查出namedtuplerename参数.

  • 这会在每次遇到JSON对象时创建一个新的*不同的*类,对吧? (8认同)
  • 这可能会导致值错误,ValueError:类型名称和字段名称不能以数字开头:'123' (7认同)
  • 作为Python的新手,我感兴趣的是,当安全性成为问题时,这是一个保存的东西. (3认同)
  • 我不知道有什么好的通用反向操作。任何单独的 namedtuple 都可以使用 `x._asdict()` 转换为 dict,这可能有助于简单的情况。 (3认同)
  • 有趣。我认为不能保证以相同的顺序迭代依赖于d.keys()和d.values(),但是我错了。[docs](https://docs.python.org/3.5/library/stdtypes.html#dictionary-view-objects)说:“如果对键,值和项视图进行了迭代,而对字典没有任何中间修改,项目的顺序将直接对应。”。对于这么小的本地代码块,要知道的是。我会添加一条注释,以明确提醒维护者这种依赖关系的代码。 (2认同)
  • 为了将通用数据加载到类型化 Python 数据类型中,我编写了一个名为“typedload”的模块。它支持嵌套、列表、集合、联合和许多其他东西。 (2认同)

Sha*_*kai 119

检查出标题为专业JSON对象解码json 模块文档.您可以使用它将JSON对象解码为特定的Python类型.

这是一个例子:

class User(object):
    def __init__(self, name, username):
        self.name = name
        self.username = username

import json
def object_decoder(obj):
    if '__type__' in obj and obj['__type__'] == 'User':
        return User(obj['name'], obj['username'])
    return obj

json.loads('{"__type__": "User", "name": "John Smith", "username": "jsmith"}',
           object_hook=object_decoder)

print type(User)  # -> <type 'type'>
Run Code Online (Sandbox Code Playgroud)

更新

如果要通过json模块访问字典中的数据,请执行以下操作:

user = json.loads('{"__type__": "User", "name": "John Smith", "username": "jsmith"}')
print user['name']
print user['username']
Run Code Online (Sandbox Code Playgroud)

就像一本普通的字典.

  • @Ben:我认为你的评论是不恰当的。目前这里的所有答案中,这是唯一一个正确的课程。这意味着:这是一次一次性操作,并且结果使用正确的类型。Pickle 本身适用于与 JSON 不同的应用程序(二进制与文本表示),并且 jsonpickle 是一个非标准库。我很想知道您如何解决 std json lib 不向对象挂钩提供上层解析树的问题 (2认同)

edd*_*eek 86

这不是代码高尔夫,但这是我最短的技巧,types.SimpleNamespace用作JSON对象的容器.

与领先的namedtuple解决方案相比,它是:

  • 可能更快/更小,因为它不会为每个对象创建一个类
  • 没有rename选项,可能对无效标识符的密钥有相同的限制(setattr在封面下使用)

例:

from __future__ import print_function
import json

try:
    from types import SimpleNamespace as Namespace
except ImportError:
    # Python 2.x fallback
    from argparse import Namespace

data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'

x = json.loads(data, object_hook=lambda d: Namespace(**d))

print (x.name, x.hometown.name, x.hometown.id)
Run Code Online (Sandbox Code Playgroud)

  • 这是最优雅的解决方案,应该在顶部. (7认同)
  • 在Python 3.x下运行时编辑使用@ maxschlepzig的解决方案(不幸的是,`types.SimpleNamespace`在2.7中不存在). (4认同)
  • 为了避免对argparse的依赖:用`from types import SimpleNamespace`替换argparse import并使用:`x = json.loads(data,object_hook = lambda d:SimpleNamespace(**d))` (3认同)
  • 顺便说一下,序列化库Marshmallow提供了与`@ post_load`装饰器类似的功能.https://marshmallow.readthedocs.io/en/latest/quickstart.html#deserializing-to-objects (2认同)

cma*_*nda 75

你可以试试这个:

class User(object):
    def __init__(self, name, username, *args, **kwargs):
        self.name = name
        self.username = username

import json
j = json.loads(your_json)
u = User(**j)
Run Code Online (Sandbox Code Playgroud)

只需创建一个新的Object,并将参数作为映射传递.

  • 这应该是公认的答案。为我工作的广告比其他所有广告都简单得多。 (2认同)

ube*_*kel 34

这是一个快速而又脏的json泡菜替代品

import json

class User:
    def __init__(self, name, username):
        self.name = name
        self.username = username

    def to_json(self):
        return json.dumps(self.__dict__)

    @classmethod
    def from_json(cls, json_str):
        json_dict = json.loads(json_str)
        return cls(**json_dict)

# example usage
User("tbrown", "Tom Brown").to_json()
User.from_json(User("tbrown", "Tom Brown").to_json()).to_json()
Run Code Online (Sandbox Code Playgroud)

  • 感谢您为json序列化和反序列化提供这样一个简单的解决方案. (4认同)
  • 应该选择它作为答案。 (2认同)

spu*_*kus 16

对于复杂对象,您可以使用JSON Pickle

用于将任意对象图序列化为JSON的Python库.它几乎可以占用任何Python对象并将对象转换为JSON.此外,它可以将对象重新构建回Python.

  • 我认为[jsonstruct](https://github.com/initialxy/jsonstruct)更好.`jsonstruct最初是jsonpickle的一个分支(谢谢大家!).这个库和jsonpickle之间的关键区别在于,在反序列化期间,jsonpickle要求将Python类型记录为JSON的一部分.此库旨在删除此要求,而是要求将类作为参数传入,以便可以检查其定义.然后它将返回给定类的实例.这种方法类似于Jackson(Java)的工作原理 (6认同)
  • jsonstruct的问题在于它似乎没有被维护(事实上,它看起来已经废弃了)并且它无法转换对象列表,例如`'[{"name":"object1"},{"name" : "Object2的"}]'`.jsonpickle也不能很好地处理它. (3认同)

lov*_*soa 10

如果您使用的是 python 3.6+,则可以使用marshmallow-dataclass。与上面列出的所有解决方案相反,它既简单又类型安全:

from marshmallow_dataclass import dataclass

@dataclass
class User:
    name: str

user = User.Schema().load({"name": "Ramirez"})
Run Code Online (Sandbox Code Playgroud)


Bož*_*vić 9

由于没有人提供像我一样的答案,我将把它发布在这里。

它是一个强大的类,可以轻松地在 JSON 之间来回转换strdict我已经从另一个问题的答案中复制了它:

import json

class PyJSON(object):
    def __init__(self, d):
        if type(d) is str:
            d = json.loads(d)

        self.from_dict(d)

    def from_dict(self, d):
        self.__dict__ = {}
        for key, value in d.items():
            if type(value) is dict:
                value = PyJSON(value)
            self.__dict__[key] = value

    def to_dict(self):
        d = {}
        for key, value in self.__dict__.items():
            if type(value) is PyJSON:
                value = value.to_dict()
            d[key] = value
        return d

    def __repr__(self):
        return str(self.to_dict())

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __getitem__(self, key):
        return self.__dict__[key]

json_str = """... JSON string ..."""

py_json = PyJSON(json_str)
Run Code Online (Sandbox Code Playgroud)


dan*_*ilo 7

改进 lovasoa 的非常好的答案。

如果您使用的是 python 3.6+,则可以使用:
pip install marshmallow-enum
pip install marshmallow-dataclass

它简单且类型安全。

您可以在 string-json 中转换您的类,反之亦然:

从对象到字符串 Json:

    from marshmallow_dataclass import dataclass
    user = User("Danilo","50","RedBull",15,OrderStatus.CREATED)
    user_json = User.Schema().dumps(user)
    user_json_str = user_json.data
Run Code Online (Sandbox Code Playgroud)

从字符串 Json 到对象:

    json_str = '{"name":"Danilo", "orderId":"50", "productName":"RedBull", "quantity":15, "status":"Created"}'
    user, err = User.Schema().loads(json_str)
    print(user,flush=True)
Run Code Online (Sandbox Code Playgroud)

类定义:

class OrderStatus(Enum):
    CREATED = 'Created'
    PENDING = 'Pending'
    CONFIRMED = 'Confirmed'
    FAILED = 'Failed'

@dataclass
class User:
    def __init__(self, name, orderId, productName, quantity, status):
        self.name = name
        self.orderId = orderId
        self.productName = productName
        self.quantity = quantity
        self.status = status

    name: str
    orderId: str
    productName: str
    quantity: int
    status: OrderStatus
Run Code Online (Sandbox Code Playgroud)

  • 您不需要构造函数,只需将 init=True 传递给数据类即可。 (2认同)

R H*_*R H 6

如果您使用的是Python 3.5+,则可以jsons用来序列化和反序列化为普通的旧Python对象:

import jsons

response = request.POST

# You'll need your class attributes to match your dict keys, so in your case do:
response['id'] = response.pop('user_id')

# Then you can load that dict into your class:
user = jsons.load(response, FbApiUser)

user.save()
Run Code Online (Sandbox Code Playgroud)

您还可以FbApiUser从继承继承以jsons.JsonSerializable获取更多的优雅:

user = FbApiUser.from_json(response)
Run Code Online (Sandbox Code Playgroud)

如果您的类由Python默认类型(例如字符串,整数,列表,日期时间等)组成,则这些示例将起作用。但是,jsonslib将需要自定义类型的类型提示。


LOs*_*KeY 6

英安岩也可能是您的解决方案,它支持以下功能:

  • 嵌套结构
  • (基本)类型检查
  • 可选字段(即打字。可选)
  • 工会
  • 前向引用
  • 收藏
  • 自定义类型挂钩

https://pypi.org/project/dacite/

from dataclasses import dataclass
from dacite import from_dict


@dataclass
class User:
    name: str
    age: int
    is_active: bool


data = {
    'name': 'John',
    'age': 30,
    'is_active': True,
}

user = from_dict(data_class=User, data=data)

assert user == User(name='John', age=30, is_active=True)
Run Code Online (Sandbox Code Playgroud)


Mil*_*vić 6

JSON 到 python 对象

以下代码以递归方式使用对象键创建动态属性。

JSON 对象 - fb_data.json

{
    "name": "John Smith",
    "hometown": {
        "name": "New York",
        "id": 123
    },
    "list": [
        "a",
        "b",
        "c",
        1,
        {
            "key": 1
        }
    ],
    "object": {
        "key": {
            "key": 1
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

关于转换我们有3种情况:

  • 列表
  • 字典(新对象)
  • bool、int、float 和 str
import json


class AppConfiguration(object):
    def __init__(self, data=None):
        if data is None:
            with open("fb_data.json") as fh:
                data = json.loads(fh.read())
        else:
            data = dict(data)

        for key, val in data.items():
            setattr(self, key, self.compute_attr_value(val))

    def compute_attr_value(self, value):
        if isinstance(value, list):
            return [self.compute_attr_value(x) for x in value]
        elif isinstance(value, dict):
            return AppConfiguration(value)
        else:
            return value


if __name__ == "__main__":
    instance = AppConfiguration()

    print(instance.name)
    print(instance.hometown.name)
    print(instance.hometown.id)
    print(instance.list[4].key)
    print(instance.object.key.key)
Run Code Online (Sandbox Code Playgroud)

现在键、值对是属性 - 对象。

输出:

John Smith
New York
123
1
1
Run Code Online (Sandbox Code Playgroud)

将 JSON 粘贴为代码

支持TypeScript、、、、、、、、、、、、、、、、、、和。Python​​​​​​​​​​​​GoRubyC#JavaSwiftRustKotlinC++FlowObjective-CJavaScriptElmJSON Schema

  • 从 JSON、JSON Schema 和 TypeScript 交互生成类型和(反)序列化代码
  • 将 JSON/JSON Schema/TypeScript 粘贴为代码

在此输入图像描述

quicktype从示例 JSON 数据推断类型,然后输出强类型模型和序列化器,以便以所需的编程语言处理该数据。

输出:

# Generated by https://quicktype.io
#
# To change quicktype's target language, run command:
#
#   "Set quicktype target language"

from typing import List, Union


class Hometown:
    name: str
    id: int

    def __init__(self, name: str, id: int) -> None:
        self.name = name
        self.id = id


class Key:
    key: int

    def __init__(self, key: int) -> None:
        self.key = key


class Object:
    key: Key

    def __init__(self, key: Key) -> None:
        self.key = key


class FbData:
    name: str
    hometown: Hometown
    list: List[Union[Key, int, str]]
    object: Object

    def __init__(self, name: str, hometown: Hometown, list: List[Union[Key, int, str]], object: Object) -> None:
        self.name = name
        self.hometown = hometown
        self.list = list
        self.object = object
Run Code Online (Sandbox Code Playgroud)

此扩展可在Visual Studio Code Marketplace中免费获得。

  • 刚刚看到你甚至可以在线使用它:[quicktype.io app](https://app.quicktype.io) (2认同)

seb*_*piq 5

我编写了一个名为any2any的小(de)序列化框架,它有助于在两种Python类型之间进行复杂的转换.

在你的情况下,我想你想要从一个字典(获得json.loads)转换为一个复杂的对象response.education ; response.name,具有嵌套的结构response.education.id等...所以这正是这个框架的制作.文档还不是很好,但通过使用any2any.simple.MappingToObject,你应该能够很容易地做到这一点.请询问您是否需要帮助.


ave*_*tat 5

我认为最轻的解决方案是

\n
import orjson  # faster then json =)\nfrom typing import NamedTuple\n\n_j = \'{"name":"\xd0\x98\xd0\xb2\xd0\xb0\xd0\xbd","age":37,"mother":{"name":"\xd0\x9e\xd0\xbb\xd1\x8c\xd0\xb3\xd0\xb0","age":58},"children":["\xd0\x9c\xd0\xb0\xd1\x88\xd0\xb0","\xd0\x98\xd0\xb3\xd0\xbe\xd1\x80\xd1\x8c","\xd0\xa2\xd0\xb0\xd0\xbd\xd1\x8f"],"married": true,\' \\\n     \'"dog":null} \'\n\n\nclass PersonNameAge(NamedTuple):\n    name: str\n    age: int\n\n\nclass UserInfo(NamedTuple):\n    name: str\n    age: int\n    mother: PersonNameAge\n    children: list\n    married: bool\n    dog: str\n\n\nj = orjson.loads(_j)\nu = UserInfo(**j)\n\nprint(u.name, u.age, u.mother, u.children, u.married, u.dog)\n\n>>> Ivan 37 {\'name\': \'Olga\', \'age\': 58} [\'Mary\', \'Igor\', \'Jane\'] True None\n
Run Code Online (Sandbox Code Playgroud)\n


tmo*_*hou 5

如果您正在寻找 JSON 或任何复杂字典的类型安全反序列化到 Python 类中,我强烈推荐Python 3.7+ 的pydantic 。它不仅具有简洁的 API(不需要编写“帮助程序”样板),可以与 Python数据类集成,而且具有复杂和嵌套数据结构的静态和运行时类型验证。

用法示例:

from pydantic import BaseModel
from datetime import datetime

class Item(BaseModel):
    field1: str | int           # union
    field2: int | None = None   # optional
    field3: str = 'default'     # default values

class User(BaseModel):
    name: str | None = None
    username: str
    created: datetime           # default type converters
    items: list[Item] = []      # nested complex types

data = {
    'name': 'Jane Doe',
    'username': 'user1',
    'created': '2020-12-31T23:59:00+10:00',
    'items': [
        {'field1': 1, 'field2': 2},
        {'field1': 'b'},
        {'field1': 'c', 'field3': 'override'}
    ]
}

user: User = User(**data)
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息和功能,请查看 pydantic文档中的有理部分。