很难说什么是"最佳实践",我个人会说,仅仅使用字典是非常常见的,除非你有一个很好的理由来定义一个类(限制:没有默认值,没有别名).这是否适用于您,取决于您打算如何使用这些数据.如果你有一本词典,把它序列化只是
import json
record = {
"Data Label": "Default Label",
"Data Value": None,
"Data Description": {
"f1": 1,
"f2":"2"
}
}
with open("my_record.json", "w") as f:
json.dump(record, f)
读到这本书
import json
with open("my_record.json", "r") as f:
record = json.load(f)
如果你来自一个遵循OO原则的语言,那么在没有类作为接口的情况下处理数据可能看起来很奇怪.但通常情况下,它只是罚款.
如果事实证明并非如此,并且您真的希望有某种模式来告诉您数据的外观/帮助IDE解决自动完成问题,您可以在现有代码中添加一个TypedDict
定义(新的限制:只有有效的Python变量名才能是键):
from typing import TypedDict, cast
import json
class MyDataContainer(TypedDict):
label: str
value: str | None
definiton: "MyDataDefinition"
class MyDataDefinition(TypedDict):
f1: int
f2: str
with open("my_record.json", "r") as f:
record = cast(MyDataContainer, json.load(f))
record[ # at this point your IDE should hint "label", "value", or "definiton"
注意:cast
不做任何事情,它只是将类型断言到工具,就像IDE一样.如果您希望对正在加载的数据进行实际的运行时判断,则需要安装第三方库,如typeguard
.首先,问问你自己——这是否真的有价值,或者你仅仅是为了"以正确的方式做事"?
如果你不能满足我概述的词典的局限性,我建议你 Select pydantic
个.它支持serializing to/deserizing from json,别名,默认值,以及更多的东西:
import pydantic
class MyDataContainer(pydantic.BaseModel):
label: str = pydantic.Field("Default Label", alias="Data Label")
value: str | None = pydantic.Field(alias="Data Value")
definiton: "MyDataDefinition" = pydantic.Field(alias="Data Description")
class MyDataDefinition(pydantic.BaseModel):
f1: int
f2: str
with open("my_record.json", "r") as f:
record = MyDataContainer(**json.load(f))
# pydantic would have complained if the json didn't comply
print(record.label) # prints: "Default Label"
print(record.model_dump_json(indent=2))
# prints:
# {
# "Data Label": "Default Label",
# "Data Value": null,
# "Data Description": {
# "f1": 1,
# "f2": "2"
# }
# }