数据类示例:
@dataclass
class StatusElement:
status: str
orderindex: int
color: str
type: str
@dataclass
class List:
id: int
statuses: List[StatusElement]
Run Code Online (Sandbox Code Playgroud)
JSON 示例:
json = {
"id": "124",
"statuses": [
{
"status": "to do",
"orderindex": 0,
"color": "#d3d3d3",
"type": "open"
}]
}
Run Code Online (Sandbox Code Playgroud)
我可以像这样解压 JSON:
object = List(**json)
Run Code Online (Sandbox Code Playgroud)
但我不确定如何将状态解压到状态对象中并附加到statusesList 对象的列表中?我确信我需要以某种方式循环它,但不确定如何将其与拆包结合起来。
rv.*_*tch 19
Pythondataclasses是一个很棒的模块,但不幸的是它不能处理的事情之一是将 JSON 对象解析为嵌套数据类结构。
对此存在一些解决方法:
from_json将 JSON 字符串转换为List具有嵌套数据类的实例。pydantic是支持此用例的流行的一个。下面是一个使用dataclass-wizard库的示例,它足以满足您的用例。它更轻pydantic,巧合的是也更快一点。它还支持自动大小写转换和类型转换(例如str到 annotated int)
下面的例子:
from dataclasses import dataclass
from typing import List as PyList
from dataclass_wizard import JSONWizard
@dataclass
class List(JSONWizard):
id: int
statuses: PyList['StatusElement']
# on Python 3.9+ you can use the following syntax:
# statuses: list['StatusElement']
@dataclass
class StatusElement:
status: str
order_index: int
color: str
type: str
json = {
"id": "124",
"statuses": [
{
"status": "to do",
"orderIndex": 0,
"color": "#d3d3d3",
"type": "open"
}]
}
object = List.from_dict(json)
print(repr(object))
# List(id=124, statuses=[StatusElement(status='to do', order_index=0, color='#d3d3d3', type='open')])
Run Code Online (Sandbox Code Playgroud)
免责声明:我是这个库的创建者(和维护者)。
从最新版本的dataclass-wizard. 使用起来非常简单;使用上面的相同示例,但我已JSONWizard完全删除其中的用法。请记住确保您不asdict从dataclasses模块导入,尽管我猜这应该恰好可以工作。
这是上面的修改版本,没有类继承:
from dataclasses import dataclass
from typing import List as PyList
from dataclass_wizard import fromdict, asdict
@dataclass
class List:
id: int
statuses: PyList['StatusElement']
@dataclass
class StatusElement:
status: str
order_index: int
color: str
type: str
json = {
"id": "124",
"statuses": [
{
"status": "to do",
"orderIndex": 0,
"color": "#d3d3d3",
"type": "open"
}]
}
# De-serialize the JSON dictionary into a `List` instance.
c = fromdict(List, json)
print(c)
# List(id=124, statuses=[StatusElement(status='to do', order_index=0, color='#d3d3d3', type='open')])
# Convert the instance back to a dictionary object that is JSON-serializable.
d = asdict(c)
print(d)
# {'id': 124, 'statuses': [{'status': 'to do', 'orderIndex': 0, 'color': '#d3d3d3', 'type': 'open'}]}
Run Code Online (Sandbox Code Playgroud)
此外,这里还提供了与dacite. 我之前不知道这个库,但它也非常容易使用(而且也不需要从任何类继承)。然而,从我个人的测试来看——使用 Python 3.9.1 的 Windows 10 Alienware PC——dataclass-wizard似乎在反序列化过程中总体表现要好得多。
from dataclasses import dataclass
from timeit import timeit
from typing import List
from dacite import from_dict
from dataclass_wizard import JSONWizard, fromdict
data = {
"id": 124,
"statuses": [
{
"status": "to do",
"orderindex": 0,
"color": "#d3d3d3",
"type": "open"
}]
}
@dataclass
class StatusElement:
status: str
orderindex: int
color: str
type: str
@dataclass
class List:
id: int
statuses: List[StatusElement]
class ListWiz(List, JSONWizard):
...
n = 100_000
# 0.37
print('dataclass-wizard: ', timeit('ListWiz.from_dict(data)', number=n, globals=globals()))
# 0.36
print('dataclass-wizard (fromdict): ', timeit('fromdict(List, data)', number=n, globals=globals()))
# 11.2
print('dacite: ', timeit('from_dict(List, data)', number=n, globals=globals()))
lst_wiz1 = ListWiz.from_dict(data)
lst_wiz2 = from_dict(List, data)
lst = from_dict(List, data)
# True
assert lst.__dict__ == lst_wiz1.__dict__ == lst_wiz2.__dict__
Run Code Online (Sandbox Code Playgroud)
我花了几个小时研究这方面的选择。没有原生 Python 功能可以执行此操作,但有一些第三方包(编写于 2022 年 11 月):
marshmallow_dataclass具有此功能(您无需在项目中以任何其他身份使用棉花糖)。它提供了良好的错误消息,并且该包得到了积极的维护。我使用了它一段时间,然后遇到了我认为将大型复杂 JSON 解析为深度嵌套数据类时出现的错误,然后不得不放弃。dataclass-wizard易于使用并且专门解决了这个用例。它有优秀的文档。一个显着的缺点是,如果尝试与数据类的联合进行匹配,它不会自动尝试为给定的 JSON 找到正确的匹配(请参阅https://dataclass-wizard.readthedocs.io/en/latest/common_use_cases/ dataclasses_in_union_types.html)。相反,它会要求您向输入 JSON 添加“标签键”,这是一个强大的解决方案,但如果您无法控制输入 JSON,则可能无法实现。dataclass-json与 类似dataclass-wizard,并且同样不会尝试匹配联合内的正确数据类。dacite是我暂时决定的选择。它具有与 类似的功能marshmallow_dataclass,至少在 JSON 解析方面如此。错误消息明显不如 清晰marshmallow_dataclass,但稍微抵消了这一点,如果您在错误发生时更容易找出问题所在pdb- 内部结构非常清晰,您可以尝试看看出了什么问题。根据其他人的说法,它相当慢,但这在我的情况下不是问题。一个“更清洁”的解决方案(在我看来)。使用英安岩
不需要继承什么。
from dataclasses import dataclass
from typing import List
from dacite import from_dict
data = {
"id": 124,
"statuses": [
{
"status": "to do",
"orderindex": 0,
"color": "#d3d3d3",
"type": "open"
}]
}
@dataclass
class StatusElement:
status: str
orderindex: int
color: str
type: str
@dataclass
class List:
id: int
statuses: List[StatusElement]
lst: List = from_dict(List, data)
print(lst)
Run Code Online (Sandbox Code Playgroud)
输出
List(id=124, statuses=[StatusElement(status='to do', orderindex=0, color='#d3d3d3', type='open')])
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
15765 次 |
| 最近记录: |