根据 官方 Pydantic 指南,
None
的值是具有默认值的可选字段的有效值。
如何更改它以使 None
值被默认值替换?
我的用例是 Pandas 数据框中的一条记录,因此某些字段可以是 None
:
from pydantic import BaseModel, field_validator
from typing import Optional, Union
import pandas as pd
import json
class Person(BaseModel):
name: str
age: Optional[int] = 10
@field_validator("age", mode="before")
@classmethod
def lower_age(cls, value: int) -> Union[int, None]:
return None if value is None or pd.isna(value) else value - 1
if __name__ == "__main__":
df_person = pd.DataFrame({
"name": ["Alice", "Bob"],
"age": [10, None]
})
person_list = df_person.to_dict(orient="records")
for p in person_list:
m = Person.model_validate(p)
print(json.dumps(m.model_dump(), indent=4))
在这个 MWE 中,我希望 Bob 得到的值为 10,而不是 null。 我知道我可以更改 field_validator 以使其返回默认值,但这意味着我必须输入 def
如果您没有使用 Pydantic,我会推荐以下结构。默认值是
__init__
的属性,而不是属性本身。
class Person:
name: str
age: int
def __init__(self, name: str, age: int = 10):
self.name = name
self.age = 10
如果您想使用像
None
这样的哨兵“明确”设置默认年龄,我会将 __init__
更改为
def __init__(self, name: str, age: Optional[int] = None):
self.name = name
if age is not None:
self.age = age
else:
self.age = 10
Pydantic 引入的问题是,它将 attribute 的类型与 __init__
用于初始化属性的
parameter的类型混为一谈。我首先要说的是,我对 Pydantic 不太熟悉,不知道什么是好的解决方法,但对于标准库
dataclasses
,我主张定义一个单独的 init var 来初始化该字段。例如,
@dataclass
class Person:
name: str
age: int = field(default=10, init=false)
age_: InitVar[Optional[int]] = None
def __post_init__(self, age_):
if age_ is not None:
self.age = age_
else:
self.age = fields(Person)[1].default
代码更多,但是
age
属性age
和提供哨兵来触发默认值分配。(类似,如果不是几乎相同,Pydantic 的代码应该是可能的。)