我正在学习 pydantic,我希望了解 Python 类及其属性与 pyndatic 模型之间的交互。
特别是,我希望定义一些实例变量,这些实例变量在创建模型后以及每次创建模型时在运行时延迟计算模型或特定字段已更新。这里有一个小的播放代码片段。
问题是:每次更改生日或年龄(假设可以根据给定值计算后者)时如何编码,然后重新评估 is_adult?
我可以仅使用 Python 的
@propertied
装饰器和 Pyndatic 的
@computed_field
来实现此目的,还是必须利用 Pyndatic 的
@model_validator
装饰器来获得此钩子行为?
from typing import Optional
from pydantic import BaseModel, model_validator, field_validator, computed_field
from datetime import datetime
class Person(BaseModel):
name: Optional[str]
birthdate: Optional[datetime]
_children_names: list[str] = []
@computed_field
@property
def children_names(self) -> list[str]:
return self._children_names
@children_names.setter
def children_names(self, values: list[str]):
self._children_names += values
@computed_field
@property
def is_adult(self) -> bool:
return self.age >= 18
@model_validator(mode="after")
def compute_age(cls, values):
birthdate = values.birthdate
values.age = datetime.today().year - birthdate.year
return values
if __name__ == "__main__":
person = {
"name": "Luca",
"birthdate": "1993-01-30",
}
p = Person.model_validate(person)
可以使用 Pydantic 的
@property
和
@<field>.setter
装饰器组合来实现此目的。不需要
@model_validator
来实现这一点。诀窍是在
age
的 setter 函数中重新计算
is_adult
属性。
这是一个演示如何操作的更新后的代码段:
from typing import Optional
from pydantic import BaseModel, computed_field
from datetime import datetime
class Person(BaseModel):
name: Optional[str]
birthdate: Optional[datetime]
_children_names: list[str] = []
@computed_field
@property
def children_names(self) -> list[str]:
return self._children_names
@children_names.setter
def children_names(self, values: list[str]):
self._children_names += values
@property
def age(self) -> int:
return datetime.today().year - self.birthdate.year if self.birthdate else 0
@age.setter
def age(self, value: int):
# 这只是一个占位符,因为我们不能直接设置年龄
# 但是,如果以某种方式更新了出生日期,我们将在那里执行计算
pass
@property
def is_adult(self) -> bool:
return self.age >= 18
if __name__ == "__main__":
person_data = {
"name": "Luca",
"birthdate": datetime(1993, 1, 30),
}
p = Person(**person_data)
print(p.age) # 打印:30
print(p.is_adult) # 打印:True
p.birthdate = datetime(2005, 1, 30) # 更新出生日期
print(p.age) # 打印:18
print(p.is_adult) # 打印:False
在此更新后的代码中:
-
我们创建了
age
作为@property
函数,该函数根据birthdate
计算年龄。 -
is_adult
也是一个@property
函数,它现在根据计算出的age
属性确定年龄。
通过这种方法,每当更新
birthdate
时,
age
和
is_adult
属性都会动态重新计算,确保它们始终保持最新状态。
请注意,我们不能直接设置
age
属性,因为它是根据
birthdate
计算得出的。如果需要,可以添加逻辑来修改
birthdate
,而不是直接更新
age
。