当前位置: 首页 > article >正文

Pydantic 动态字段:使用和不使用 `@computed_field` 的对比指南

Pydantic 动态字段:使用和不使用 `@computed_field` 的对比指南

    • 安装 Pydantic
    • 不使用 `@computed_field` 的实现
      • 特性
    • 使用 `@computed_field` 的实现
      • 特性
    • 使用和不使用 `@computed_field` 的对比
    • 适用场景分析
      • 什么时候不需要 `@computed_field`?
      • 什么时候使用 `@computed_field`?
    • 总结

在数据建模时,我们经常需要定义动态字段,基于模型中其他字段计算出结果。
Pydantic 提供了一个专门的装饰器 @computed_field,用于声明这样的动态字段。但即使不使用 @computed_field,也能通过普通的 Python 属性实现类似的效果。

本文将通过两种实现方式的对比,帮助你理解何时选择 @computed_field,以及它的优势。


安装 Pydantic

确保已安装最新版本的 Pydantic:

pip install pydantic

不使用 @computed_field 的实现

我们可以通过普通的 Python @property 定义动态字段:

from pydantic import BaseModel, Field

class LLMUsageMetrics(BaseModel):
    """LLM request usage metrics."""

    input_tokens: int = Field(0, description="Used input tokens by the request")
    output_tokens: int = Field(0, description="Used output tokens by the request")

    @property
    def total_tokens(self) -> int:
        """Total tokens used by the request."""
        return self.input_tokens + self.output_tokens

# 测试
metrics = LLMUsageMetrics(input_tokens=100, output_tokens=50)
print(metrics.total_tokens)  # 输出: 150

特性

  1. 动态计算: total_tokens 每次访问时都会重新计算值。
  2. 不会出现在序列化输出中: 默认情况下,@property 定义的字段不会包含在 .model_dump().model_dump_json() 输出中。
print(metrics.model_dump())
# 输出: {'input_tokens': 100, 'output_tokens': 50}  # 没有 total_tokens

如果想将其包含在输出中,可以手动在模型方法中添加逻辑。


使用 @computed_field 的实现

Pydantic 的 @computed_field 是专为动态字段设计的:

from pydantic import BaseModel, Field, computed_field

class LLMUsageMetrics(BaseModel):
    """LLM request usage metrics."""

    input_tokens: int = Field(0, description="Used input tokens by the request")
    output_tokens: int = Field(0, description="Used output tokens by the request")

    @computed_field()
    @property
    def total_tokens(self) -> int:
        """Total tokens used by the request."""
        return self.input_tokens + self.output_tokens

# 测试
metrics = LLMUsageMetrics(input_tokens=100, output_tokens=50)
print(metrics.total_tokens)  # 输出: 150
print(metrics.model_dump())
# 输出: {'input_tokens': 100, 'output_tokens': 50, 'total_tokens': 150}

特性

  1. 动态计算:@property 一样,每次访问时都会重新计算值。
  2. 自动出现在序列化输出中: @computed_field 定义的字段会自动包含在 .model_dump().model_dump_json() 输出中。

使用和不使用 @computed_field 的对比

特性不使用 @computed_field使用 @computed_field
定义方式使用普通的 @property使用 @computed_field@property 结合
动态计算每次访问时动态计算每次访问时动态计算
序列化输出默认不包含在 .model_dump().model_dump_json()自动包含在 .model_dump().model_dump_json()
使用场景需要简单动态字段,但不需要出现在序列化输出中需要动态字段且希望在序列化中体现
额外配置选项不支持支持 include_in_schema 等选项控制序列化行为

适用场景分析

什么时候不需要 @computed_field

  1. 只读属性: 如果动态字段只是为了在代码中访问,而不需要序列化输出。
  2. 灵活控制输出逻辑: 通过覆盖 .model_dump() 方法手动添加动态字段。

例如:

class LLMUsageMetrics(BaseModel):
    input_tokens: int = Field(0)
    output_tokens: int = Field(0)

    @property
    def total_tokens(self) -> int:
        return self.input_tokens + self.output_tokens

    def model_dump(self, *args, **kwargs):
        base_dict = super().model_dump(*args, **kwargs)
        base_dict['total_tokens'] = self.total_tokens
        return base_dict

metrics = LLMUsageMetrics(input_tokens=100, output_tokens=50)
print(metrics.model_dump())
# 输出: {'input_tokens': 100, 'output_tokens': 50, 'total_tokens': 150}

什么时候使用 @computed_field

  1. 自动序列化输出: 动态字段需要出现在 .model_dump().model_dump_json() 输出中。
  2. 清晰的字段文档: @computed_field 支持额外的配置选项,如 descriptioninclude_in_schema,提升可读性和可维护性。

总结

  1. 不使用 @computed_field 可以满足简单的动态字段需求,但需要手动处理序列化输出逻辑。
  2. 使用 @computed_field 能自动包含动态字段到序列化输出中,且提供更多配置选项,适合更复杂的场景。

http://www.kler.cn/a/429398.html

相关文章:

  • Scala语言的多线程编程
  • AWS Lambda
  • 内联变量(inline variables):在多个文件中共享全局常量
  • electron 打包后的 exe 文件,运行后是空白窗口
  • vue中的那些事(刷新+key+v-if,v-for)
  • css实现响应式详解
  • 如何使用 JavaScript 获取页面滚动位置?
  • Java项目实战II基于微信小程序的跑腿系统(开发文档+数据库+源码)
  • Hasura 中间件API go操作示例
  • 专为高性能汽车设计的Armv9架构的Neoverse V3AE CPU基础知识与软件编码特性解析
  • 管理系统前端框架开发案例学习
  • redis-stack redisSearch环境安装搭建
  • 记录一下,解决js内存溢出npm ERR! code ELIFECYCLEnpm ERR! errno 134 以及 errno 9009
  • 智创 AI 新视界 -- AI 引领下的未来社会变革预测(16 - 6)
  • DP协议:术语表
  • Vue 3初始化工程
  • 从模型到实际:人工智能项目落地的关键要素
  • 【深度学习】深刻理解BERT
  • 4.长度最小的子数组:
  • Text2SQL(NL2sql)对话数据库:设计、实现细节与挑战
  • 上传word表格识别出table表格 转为二维数组并显示(vue)
  • C# 中的异常处理:构建健壮和可靠的程序
  • 简单易懂讲解LVM
  • 从方向导数到梯度:深度学习中的关键数学概念详解
  • 在ARM Linux应用层下使用SPI驱动WS2812
  • 数据结构 (36)各种排序方法的综合比较