首页 > 编程问答 >每次更新模型/字段时,如何在运行时延迟计算某些属性?

每次更新模型/字段时,如何在运行时延迟计算某些属性?

时间:2024-07-30 16:57:28浏览次数:9  
标签:python pydantic

我正在学习 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

标签:python,pydantic
From: 78797418

相关文章

  • Python - Creating alternative initializers using class Methods
    Classmethodsallowustodefinealternativeinitializers(alsoknownasfactorymethods)inaclass.Thesemethodshelpuscreateinstanceobjectsfromdifferenttypesofinputdata.Letusunderstandthiswiththehelpofanexample.Again,wetakethe......
  • 如何让 Python 请求信任自签名 SSL 证书?
    importrequestsdata={'foo':'bar'}url='https://foo.com/bar'r=requests.post(url,data=data)如果URL使用自签名证书,则会失败requests.exceptions.SSLError:[Errno1]_ssl.c:507:error:14090086:SSLroutines:SSL3_GET_SERVER_CERTIF......
  • python 偏函数
    如下代码loop=tornado.ioloop.IOLoop.current()ctx=contextvars.copy_context()func_call=functools.partial(ctx.run,func,*args,**kwargs)returnawaitloop.run_in_executor(executor,func_call)偏函数一个函数作为模板,通过提供部分参数来产生一个新的函数。......
  • Chapter 18 Python异常
    欢迎大家订阅【Python从入门到精通】专栏,一起探索Python的无限可能!文章目录前言一、什么是异常二、捕获异常三、异常的传递前言在Python中,异常是一种特定的对象,能够在程序运行过程中被抛出和处理。有效地管理异常不仅可以增强程序的稳定性,还可以提高用户体验,使程......
  • Python正则表达式匹配数字的第一次重复
    示例:For0123123123,1应匹配,因为第二个1出现在任何其他数字重复之前。For01234554321,5应该匹配,因为第二个5出现在任何其他数字的重复之前。我尝试过的一些正则表达式:......
  • 当 python 极坐标中某些列条目为空时,如何分解 List[_] 列?
    给定如下所示的Polarsdf,如何在两列上调用explode(),同时将空条目扩展到正确的长度以与其行匹配?shape:(3,2)┌───────────┬─────────────────────┐│x┆y││---┆---......
  • 使用python从网站自动下载pdf时出错
    我想从一个名为epadossier.nl的网站自动批量下载pdf我用谷歌搜索了这个并找到了一段代码并修复了一个小错误。所以现在我得到了这个`importrequestsurl="https://www.epadossier.nl/adres/plaats/straat/num"response=requests.get(url)ifresponse.status_cod......
  • 避免字符串连接的嵌套循环的 Pythonic 方法
    我想找到所有5位数字的字符串,其中前三位数字在我的第一个列表中,第二个槽第四个数字在我的第二个列表中,第三到第五个数字在我的最后一个列表中:l0=["123","567","451"]l1=["234","239","881"]l2=["348","551","399"......
  • Python 环境配置(二)安装jupyter、matplotlib、numpy库
    Python环境配置(二)安装jupyter、matplotlib、numpy库一、numpypipinstallnumpy二、matplotlibpipinstallmatplotlib三、jupyter1、anaconda自带Jupyter2、pycharm插件只有Pycharm的Professional版才支持JupyterNotebook,请注意版本3、新建文件#%......
  • 如何使用 PIPE 并行运行 python 子进程?
    我正在使用inkscape将一堆SVG图像转换为PNG。单线程:importsubprocessimporttimeimportosinkscape_path=r'C:\ProgramFiles\Inkscape\bin\inkscape.com'steps=30filenames=[]processes=[]#t_start=time.process_time()t_start=time.time()f......