对Python有点不熟悉. 我来自C#世界,我试图找出在Python中创建数据 struct 的最佳实践是什么:

  1. 可以有空字段(无)
  2. 可以为某些字段指定默认值
  3. 可以为序列化期间使用的字段分配别名

例如,在C#中,我可以这样做:

using Newtonsoft.Json;
public class MyDataClass
{
    [JsonProperty(PropertyName = "Data Label")]
    public string label { get; set; }

    [JsonProperty(PropertyName = "Data Value")]
    public string value { get; set; }

    [JsonProperty(PropertyName = "Data Description")]
    public MyDataDefinition definiton { get; set; }

    public MyDataClass
    {
        this.label = "Default Label";
    }
}

有了这个类,我可以创建一个只预填充一个字段的实例,并随意填充数据 struct 的其余部分,然后用修饰的别名字段名称将其序列化为JSON.

在Python中,我try 了几个包,但每次我都得到了超级复杂的实现,并没有满足所有需求. 我一定错过了一些非常基本的东西,因为它看起来像是一个简单而常见的用例.

你会如何以最"Python "的方式实现这样的东西?

推荐答案

很难说什么是"最佳实践",我个人会说,仅仅使用字典是非常常见的,除非你有一个很好的理由来定义一个类(限制:没有默认值,没有别名).这是否适用于您,取决于您打算如何使用这些数据.如果你有一本词典,把它序列化只是

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" 
#   } 
# }

Python相关问答推荐

使用pandas、matplotlib和Yearbox绘制时显示错误的年份

Python中使用时区感知日期时间对象进行时间算术的Incredit

Polars比较了两个预设-有没有方法在第一次不匹配时立即失败

ModuleNotFound错误:没有名为flags.State的模块; flags不是包

. str.替换pandas.series的方法未按预期工作

在线条上绘制表面

数据抓取失败:寻求帮助

无法定位元素错误404

如何使用Python以编程方式判断和检索Angular网站的动态内容?

为一个组的每个子组绘制,

字符串合并语法在哪里记录

Python逻辑操作作为Pandas中的条件

SQLAlchemy bindparam在mssql上失败(但在mysql上工作)

为什么numpy. vectorize调用vectorized函数的次数比vector中的元素要多?

Gekko中基于时间的间隔约束

根据客户端是否正在传输响应来更改基于Flask的API的行为

BeautifulSoup-Screper有时运行得很好,很健壮--但有时它失败了::可能这里需要一些更多的异常处理?

Python:从目录内的文件导入目录

Regex用于匹配Python中逗号分隔的AWS区域

我如何为测试函数的参数化提供fixture 生成的数据?如果我可以的话,还有其他 Select 吗?