Python: Annotated和Pydantic

13 min read

Annotated

typing.Annotated 在 Python3.9 版中引入,用于为类型注解添加元数据。作为 PEP 593 -- Flexible function and variable annotations 的一部分被添加到 typing 模块中。使用 AnnotatedPython 环境必须是 3.9 或更高版本。


typing.Annotated 的核心作用是为现有的 Python 类型添加元数据(metadata)。它本身并不执行任何运行时的类型检查或验证。可以将 Annotated 看作是一个类型装饰器,它允许你将额外的信息(可以是任何 Python 对象) 与一个类型关联起来。


这个设计的主要目的是为了让第三方工具能够更好地理解类型注解,从而提供更丰富的功能,例如类型检查、文档生成等,且无需修改 Python 的核心类型系统。通过使用 Annotated,开发者可以更灵活地表达类型信息,使代码更加清晰和可维护,

Pydantic

Pydantic 是一个 Python 库,主要用于数据验证和解析。它通过 Python 的类型提示 (type hints) 来定义数据的结构,并在运行时验证数据的有效性。


以下是 Pydantic 的主要用途和优点:


  • 数据验证 (Data Validation): 这是 Pydantic 最核心的功能。你可以使用 Pydantic 模型清晰地定义预期的数据结构和类型。当接收到外部数据(例如,来自 API 请求、配置文件、用户输入等)时,Pydantic 会自动根据你定义的模型进行验证。如果数据不符合预期类型或约束,Pydantic 会抛出详细的错误信息,告诉你哪些字段出了问题以及具体原因。

  • 数据解析 (Data Parsing): 除了验证,Pydantic 还能将输入数据解析成 Python 对象。即使输入数据是字符串、数字或其他格式,Pydantic 也会尝试将其转换为模型中定义的 Python 类型。例如,一个字符串 “123” 可以被解析成 int 类型。

  • 数据序列化 (Data Serialization): Pydantic 模型可以将 Python 对象序列化为其他格式,如 JSON。这对于构建 API 接口非常有用,因为你需要将 Python 对象转换为 JSON 格式发送给客户端。

  • 类型提示的强大利用: Pydantic 充分利用了 Python 3.6+ 引入的类型提示。通过类型提示,你可以清晰地表达数据的预期结构,这不仅方便了 Pydantic 的验证和解析,也提高了代码的可读性和可维护性,并能与 MyPy 等静态类型检查工具良好集成。

  • JSON Schema 生成: Pydantic 可以根据你的模型自动生成 JSON Schema。JSON Schema 是一种描述 JSON 数据结构的标准化方式,这对于 API 文档生成和与其他系统进行数据交互非常有用。

  • 与 Web 框架集成: Pydantic 与许多流行的 Python Web 框架(如 FastAPI、Starlette)无缝集成。FastAPI 甚至在底层 heavily rely on Pydantic 来处理请求和响应的数据验证和序列化。

  • 自定义验证器 (Custom Validators): 除了基本的类型验证,Pydantic 还允许你定义自定义的验证逻辑,以满足更复杂的业务规则。你可以编写函数来检查字段的值是否符合特定的要求。

  • 数据清洗和转换 (Data Cleaning and Transformation): 在验证过程中,Pydantic 还可以对数据进行清洗和转换。例如,你可以定义将字符串自动去除首尾空格,或者将日期字符串转换为 datetime 对象。


总而言之,Pydantic 主要用于确保你的 Python 应用程序接收和处理的数据是有效和符合预期的。它可以帮助你减少因数据格式错误而引发的 bug,提高代码的健壮性和可靠性,并简化数据处理相关的开发工作。


一些常见的应用场景包括:


  • API 开发: 验证和解析 API 请求的输入数据,以及序列化 API 的输出数据。
  • 数据处理管道: 确保从不同来源读取的数据符合预期的格式和类型。
  • 配置文件解析: 加载和验证应用程序的配置文件。
  • 用户输入验证: 验证 Web 表单或命令行工具接收到的用户输入。
  • 机器学习模型的数据预处理: 确保输入模型的数据具有正确的结构和类型。

总结:

  • typing.Annotated: 是 Python 类型提示系统的一部分,提供了一种为现有类型添加元数据的标准方法。它本身不执行任何运行时操作,而是让第三方工具能够读取和利用这些额外的元数据。
  • Pydantic: 专注于数据建模、验证、解析和序列化,通过定义 Pydantic 模型并利用类型提示来实现这些功能。它是一个功能强大的库,用于处理外部数据并确保其符合预期的结构和类型。

在实际应用中,Annotated 经常和 Pydantic 组合使用,以增强 Pydantic 模型的功能。虽然 Pydantic 也可以单独使用,但结合 Annotated 可以提供更灵活和标准化的方式来定义模型的行为。

单独使用 Pydantic 的情况:

基本的数据验证和解析: 当你只需要定义数据的基本结构和类型,并进行简单的验证和解析时,可以直接使用 Pydantic 模型。例如:


BaseModel

from pydantic import BaseModel

class User(BaseModel):
    id: int
    name: str
    signup_ts: float | None = None

在这种情况下,Pydantic 会根据类型提示自动进行类型检查和基本的数据转换。


Field


函数参数和返回值注释 (使用 Field):

from pydantic import Field

def search_database(
    query: str = Field(description="Search query string"),
    limit: int = Field(10, description="Maximum number of results", ge=1, le=100)
) -> list:
    ...

与这种方式相比,如果只需要需要定义简单的数据结构,并且不需要复杂的验证或序列化,可以直接使用 Python 的类型提示:

def search_database(
    query: str,
    limit: int,
) -> list:
    ...
  • 优点:
    • 结构化数据: Field 来自 pydantic 或类似的库,它允许你定义更丰富的数据类型信息,例如描述、默认值、验证规则(ge, le)。
    • 自动化文档和验证: 这些信息可以被用于自动生成 API 文档(例如使用 FastAPI),以及在运行时进行数据验证。
    • IDE 支持: 现代 IDE 可以利用这些信息提供更好的代码提示和错误检查。
  • 缺点:
    • 依赖外部库: 你需要引入 pydantic 或类似的库。
    • 更冗长: 代码量相对较多,对于简单的类型注释可能显得过于繁琐。

AnnotatedField 结合使用

from typing import Annotated
from pydantic import Field

def analyze_metrics(
    # number with range constraints
    count: Annotated[int, Field(description="数据数量", ge=1, le=100)],
    ratio: Annotated[float, Field(description="比率", ge=0, le=1)],
    # String with pattern and length constraints
    user_id: Annotated[
        str, Field(description="用户ID 格式: XX0000", pattern=r"^[a-z]{2}\d{4}$")
    ],
    comment: Annotated[str, Field(description="备注", min_len=3, max_length=500)] = "",
    factor: Annotated[float, Field(description="因子", multiple_of=5)] = 10,
) -> dict[str, float]:
    """分析一组数据的统计信息."""
    pass
  • 优点:
    • 类型提示和元数据: 使用 Annotated 可以将类型提示与元数据(例如 Field)结合起来。
    • 灵活性: 允许你添加多个元数据,不仅限于描述和验证规则。
    • 标准化: Annotated 是 Python 3.9 引入的标准库 typing 的一部分,因此不需要额外的依赖(除非 Field 来自外部库)。
  • 缺点:
    • 可读性略差: 相对于简单的类型提示,Annotated 的语法可能稍微复杂一些。
    • 需要 Python 3.9+: Annotated 是 Python 3.9 引入的特性。

选择策略

Annotated 通常与 Pydantic 结合使用,以增强 Pydantic 模型字段的定义,添加自定义验证逻辑、元数据等。

  • 基本数据建模: 如果你只需要定义简单的数据结构,并且不需要复杂的验证或序列化,可以直接使用 Python 的类型提示。

  • 数据验证和解析: 如果你需要对输入数据进行严格的验证和解析,并将其转换为 Python 对象,选择 Pydantic。

  • 自定义验证和元数据: 如果你需要在 Pydantic 模型中添加自定义的验证逻辑或额外的元数据(例如字段描述、别名、格式等),那么使用 Annotated 结合 Pydantic 是推荐的做法。

  • 第三方库集成: 如果你使用的第三方库支持 Annotated,并且你想利用类型提示中的元数据来配置这些库的行为,那么可以使用 Annotated。例如,Pydantic 利用 Annotated 来支持自定义验证器 (PlainValidator) 和字段配置 (Field).

Last updated on 2025-05-18