如何将 json 文件转换为 python class?
How do I convert a json file to a python class?
考虑这个名为 h.json
的 json 文件,我想将其转换为 python 数据 class.
{
"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])
但这仅限于数据中定义的参数(电子邮件、姓名等)class。
如果我要修改 json 以包含另一项内容(比如年龄)怎么办?
该脚本最终会返回一个 TypeError
,特别是 TypeError: __init__() got an unexpected keyword argument 'age'
.
有没有办法根据dict(json对象)的key动态调整class属性,这样我就不用每次加一个属性了json?
的新密钥
对于平面(非嵌套数据class),下面的代码可以完成工作。
如果您需要处理嵌套数据classes,您应该使用像dacite
.
这样的框架
注意 1 从 json 文件加载数据不应成为您 class 逻辑的一部分。
注 2 如果您的 json 可以包含任何内容 - 您不能将其映射到数据 class 并且您应该使用 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)]
这样你会失去一些 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)
因为听起来您的数据可能是动态的,并且您希望在 JSON 对象中自由添加更多字段而不反映模型中的相同更改,我还建议检查输出 typing.TypedDict
而不是 dataclass
.
这是一个 TypedDict
的例子,它应该在 Python 3.7+ 中工作。由于 TypedDict 是 introduced in 3.8, I've instead imported it from 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'])
如果您 开始使用数据classes 来为您的数据建模,我建议您查看 JSON 序列化库,例如 dataclass-wizard 如前所述,它应该处理 JSON 数据中的无关字段,以及嵌套数据 class 模型(如果您发现数据变得更加复杂)。
它还有一个方便的工具,可用于从 JSON 数据生成数据class 模式,例如,如果您想更新模型 class 每当您如前所述在 JSON 文件中添加新字段时。
考虑这个名为 h.json
的 json 文件,我想将其转换为 python 数据 class.
{
"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])
但这仅限于数据中定义的参数(电子邮件、姓名等)class。
如果我要修改 json 以包含另一项内容(比如年龄)怎么办?
该脚本最终会返回一个 TypeError
,特别是 TypeError: __init__() got an unexpected keyword argument 'age'
.
有没有办法根据dict(json对象)的key动态调整class属性,这样我就不用每次加一个属性了json?
的新密钥对于平面(非嵌套数据class),下面的代码可以完成工作。
如果您需要处理嵌套数据classes,您应该使用像dacite
.
这样的框架
注意 1 从 json 文件加载数据不应成为您 class 逻辑的一部分。
注 2 如果您的 json 可以包含任何内容 - 您不能将其映射到数据 class 并且您应该使用 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)]
这样你会失去一些 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)
因为听起来您的数据可能是动态的,并且您希望在 JSON 对象中自由添加更多字段而不反映模型中的相同更改,我还建议检查输出 typing.TypedDict
而不是 dataclass
.
这是一个 TypedDict
的例子,它应该在 Python 3.7+ 中工作。由于 TypedDict 是 introduced in 3.8, I've instead imported it from 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'])
如果您 开始使用数据classes 来为您的数据建模,我建议您查看 JSON 序列化库,例如 dataclass-wizard 如前所述,它应该处理 JSON 数据中的无关字段,以及嵌套数据 class 模型(如果您发现数据变得更加复杂)。
它还有一个方便的工具,可用于从 JSON 数据生成数据class 模式,例如,如果您想更新模型 class 每当您如前所述在 JSON 文件中添加新字段时。