如何将 json 文件转换为 python 类?
Posted
技术标签:
【中文标题】如何将 json 文件转换为 python 类?【英文标题】:How do I convert a json file to a python class? 【发布时间】:2021-12-14 19:17:37 【问题描述】:考虑这个名为 h.json
的 json 文件,我想将其转换为 python 数据类。
"acc1":
"email":"acc1@example.com",
"password":"acc1",
"name":"ACC1",
"salary":1
,
"acc2":
"email":"acc2@example.com",
"password":"acc2",
"name":"ACC2",
"salary":2
我可以使用替代构造函数来获取每个帐户,例如:
import json
from dataclasses import dataclass
@dataclass
class Account(object):
email:str
password:str
name:str
salary:int
@classmethod
def from_json(cls, json_key):
file = json.load(open("h.json"))
return cls(**file[json_key])
但这仅限于在数据类中定义的参数(电子邮件、姓名等)。
如果我要修改 json 以包含其他内容,比如年龄,该怎么办?
该脚本最终会返回一个TypeError
,特别是TypeError: __init__() got an unexpected keyword argument 'age'
。
有没有办法根据dict(json对象)的key来动态调整class属性,这样就不用每次给json添加新key时都要添加属性了?
【问题讨论】:
为了获得这种灵活性,最好将数据保存为 dict,而不是尝试将其放入类中。 数据类的意义在于它使您无法像这样定义新字段。如果要动态更改可以定义哪些字段,可以使用类。 【参考方案1】:这样你会失去一些dataclass
功能。
optional
如自动完成功能
但是,您更熟悉您的项目并做出相应决定
方法肯定有很多,但这是其中之一:
@dataclass
class Account(object):
email: str
password: str
name: str
salary: int
@classmethod
def from_json(cls, json_key):
file = json.load(open("1.txt"))
keys = [f.name for f in fields(cls)]
# or: keys = cls.__dataclass_fields__.keys()
json_data = file[json_key]
normal_json_data = key: json_data[key] for key in json_data if key in keys
anormal_json_data = key: json_data[key] for key in json_data if key not in keys
tmp = cls(**normal_json_data)
for anormal_key in anormal_json_data:
setattr(tmp,anormal_key,anormal_json_data[anormal_key])
return tmp
test = Account.from_json("acc1")
print(test.age)
【讨论】:
__dataclass_fields__
属性是数据类模块的内部属性,可以随时更改;您应该更喜欢在此处使用dataclasses.fields
(已记录)。
@rv.kvetch tank ,但对于这种用法无关紧要
@rv.kvetch 是的,这是真的,坦克?
@rv.kvetch 现在你不能在没有密码或电子邮件的情况下创建新的Account
对象,或者......因为这些是必填字段,但age
现在是可选的,例如如果你想更改@ 987654328@ 作为可选字段(意味着:可以在参数中不通过 email
字段的情况下创建新的Account
)您必须将第 3 行更改为:email: Optional[str]
是的@Kanishk,对不起【参考方案2】:
由于听起来您的数据可能是动态的,并且您希望在 JSON 对象中添加更多字段而不反映模型中的相同更改,因此我还建议您查看 typing.TypedDict
而不是dataclass
.
这是一个 TypedDict
的示例,它应该在 Python 3.7+ 中工作。由于 TypedDict 是 introduced in 3.8,我改为从 typing_extensions
导入它,因此它与 3.7 代码兼容。
from __future__ import annotations
import json
from io import StringIO
from typing_extensions import TypedDict
class Account(TypedDict):
email: str
password: str
name: str
salary: int
json_data = StringIO("""
"acc1":
"email":"acc1@example.com",
"password":"acc1",
"name":"ACC1",
"salary":1
,
"acc2":
"email":"acc2@example.com",
"password":"acc2",
"name":"ACC2",
"salary":2,
"someRandomKey": "string"
""")
data = json.load(json_data)
name_to_account: dict[str, Account] = data
acct = name_to_account['acc2']
# Your IDE should be able to offer auto-complete suggestions within the
# brackets, when you start typing or press 'Ctrl + Space' for example.
print(acct['someRandomKey'])
如果您开始使用数据类对数据建模,我建议您查看像 dataclass-wizard 这样的 JSON 序列化库,它应该处理 JSON 数据中的无关字段,如如果您发现数据变得更加复杂,还可以使用嵌套数据类模型。
它还有一个方便的工具,您可以使用该工具从 JSON 数据生成数据类架构,例如,如果您想在上述 JSON 文件中添加新字段时更新您的模型类,该工具非常有用。
【讨论】:
哇,TypedDict
!!!好主意
是的,绝对同意,这很酷,但我觉得typing
的一个不太知名的功能:-)
@rv.kvetch,这肯定会派上用场,感谢您让我知道,但是对于我的特定用例,除了 alt 构造函数之外,Account
类中还有许多其他方法,并从TypedDict
继承限制为仅在类中使用注释,而且我没有得到“someRandomKey”的类型提示,因为我没有在类中指定该字段。感谢您让我知道这一点。
啊,这绝对是有道理的。是的,同意,TypedDict
的一个限制是您不能像往常一样定义和使用方法。如果您仍然仍然使用数据类,我建议您查看上面的链接库,因为它有一个 CLI 工具,您可以使用它来将 JSON 模式转换为数据类模型,这可能会被使用如果你添加了一堆新的 JSON 字段。实际上,它的部分灵感来自这里的另一个优秀工具:russbiggs.github.io/json2dataclass【参考方案3】:
对于平面(非嵌套数据类),下面的代码可以完成这项工作。
如果您需要处理嵌套的数据类,您应该使用像 dacite
这样的框架。注意 1 从 json 文件加载数据不应该是您的类逻辑的一部分。
注意 2 如果您的 json 可以包含任何内容 - 您不能将其映射到数据类,您应该使用 dict
from dataclasses import dataclass
from typing import List
data =
"acc1":
"email":"acc1@example.com",
"password":"acc1",
"name":"ACC1",
"salary":1
,
"acc2":
"email":"acc2@example.com",
"password":"acc2",
"name":"ACC2",
"salary":2
@dataclass
class Account:
email:str
password:str
name:str
salary:int
accounts: List[Account] = [Account(**x) for x in data.values()]
print(accounts)
输出
[Account(email='acc1@example.com', password='acc1', name='ACC1', salary=1), Account(email='acc2@example.com', password='acc2', name='ACC2', salary=2)]
【讨论】:
我打算对obj.__dict__.update(x)
做同样的事情,但这样更好。以上是关于如何将 json 文件转换为 python 类?的主要内容,如果未能解决你的问题,请参考以下文章