如何在Pydantic中实现模型/字段更新时的运行时惰性计算属性?
实现Pydantic模型字段更新时自动重新计算is_adult
直接用Pydantic v2+提供的@computed_field就能实现需求,Python的@property也能达到效果,但@computed_field更贴合Pydantic的生态,不需要借助@model_validator——这个装饰器主要用于初始化或验证阶段的逻辑,不是字段更新后的自动计算钩子。
方案1:使用@computed_field(推荐)
@computed_field支持通过depends_on参数指定依赖字段,当这些字段的值被修改时,计算字段会自动重新求值。如果需要惰性计算(只在第一次访问或依赖字段变化后计算),还可以加上cache=True参数。
示例代码:
from datetime import date from pydantic import BaseModel, computed_field class Person(BaseModel): birthdate: date | None = None age: int | None = None @computed_field(depends_on=["birthdate", "age"], return_type=bool) def is_adult(self) -> bool: # 优先用age判断,没有则通过birthdate计算 if self.age is not None: return self.age >= 18 elif self.birthdate is not None: today = date.today() age = today.year - self.birthdate.year if (today.month, today.day) < (self.birthdate.month, self.birthdate.day): age -= 1 return age >= 18 return False # 测试 p = Person(birthdate=date(2005, 1, 1)) print(p.is_adult) # 输出True(假设当前年份>=2023) # 修改birthdate,自动重新计算is_adult p.birthdate = date(2010, 1, 1) print(p.is_adult) # 输出False # 修改age,自动重新计算is_adult p.age = 20 print(p.is_adult) # 输出True
方案2:使用Python的@property
Python原生的@property也能实现动态计算,每次访问is_adult时都会重新执行逻辑,自然会响应birthdate或age的变化。但需要注意,如果要让这个属性在模型序列化(比如model_dump())时被包含,需要在model_config里设置include={"is_adult"}。
示例代码:
from datetime import date from pydantic import BaseModel class Person(BaseModel): birthdate: date | None = None age: int | None = None model_config = {"include": {"is_adult"}} # 序列化时包含is_adult @property def is_adult(self) -> bool: if self.age is not None: return self.age >= 18 elif self.birthdate is not None: today = date.today() age = today.year - self.birthdate.year if (today.month, today.day) < (self.birthdate.month, self.birthdate.day): age -= 1 return age >= 18 return False # 测试 p = Person(age=17) print(p.is_adult) # 输出False p.age = 18 print(p.is_adult) # 输出True p.birthdate = date(2000, 1, 1) print(p.is_adult) # 输出True
关于@model_validator的说明
@model_validator(比如mode="after")只能在模型初始化或调用model_validate()时触发,无法监听模型创建后字段的动态修改,所以完全不需要用它来实现这个需求。
内容的提问来源于stack exchange,提问作者Luca
相关产品推荐
相关产品推荐

