跳转至

实验功能

在本节中,您将找到 Pydantic 中新增的、实验性功能的文档。这些功能可能会发生变化或删除,我们在将它们作为 Pydantic 的永久部分之前,正在寻找反馈和建议。

有关实验性功能的更多信息,请查看我们的版本策略。

反馈

我们欢迎对实验性功能的反馈!请在 Pydantic GitHub 存储库中打开一个问题,分享您的想法、请求或建议。

我们也鼓励你阅读现有的反馈,并添加你的想法到现有的问题。

进口警示

当你从 experimental 模块导入实验性功能时,你会看到一个警告消息,提示该功能是实验性的。你可以使用以下方法禁用此警告:

import warnings

from pydantic import PydanticExperimentalWarning

warnings.filterwarnings('ignore', category=PydanticExperimentalWarning)

管道 API

Pydantic v2.8.0 引入了一个实验性的“管道” API,该 API 允许以比现有 API 更类型安全的方式组合解析(验证)、约束和转换。此 API 可能会发生更改或删除,我们在将其作为 Pydantic 的永久部分之前,正在寻找反馈和建议。

API 文档

pydantic.experimental.pipeline

通常,管道 API 用于在验证期间定义要应用于传入数据的一系列步骤。管道 API 的设计比现有的 Pydantic API 更具类型安全性和可组合性。

每个管道中的步骤都可以是:

  • 对提供的类型运行 pydantic 验证的验证步骤

  • 转换步骤,修改数据

  • 一个根据条件检查数据的约束步骤

  • 一个谓词步骤,该步骤根据条件检查数据,如果返回 False ,则引发错误

请注意,以下示例试图以复杂性为代价进行详尽的尝试:如果您发现自己在类型注释中编写了这么多转换,您可能需要考虑使用 UserInUserOut 模型(如下例所示)或类似的方法,通过惯用的纯 Python 代码进行转换。这些 API 适用于代码节省显著且增加的复杂性相对较小的情况。

from __future__ import annotations

from datetime import datetime

from typing_extensions import Annotated

from pydantic import BaseModel
from pydantic.experimental.pipeline import validate_as, validate_as_deferred


class User(BaseModel):
    name: Annotated[str, validate_as(str).str_lower()]  # (1)!
    age: Annotated[int, validate_as(int).gt(0)]  # (2)!
    username: Annotated[str, validate_as(str).str_pattern(r'[a-z]+')]  # (3)!
    password: Annotated[
        str,
        validate_as(str)
        .transform(str.lower)
        .predicate(lambda x: x != 'password'),  # (4)!
    ]
    favorite_number: Annotated[  # (5)!
        int,
        (validate_as(int) | validate_as(str).str_strip().validate_as(int)).gt(
            0
        ),
    ]
    friends: Annotated[list[User], validate_as(...).len(0, 100)]  # (6)!
    family: Annotated[  # (7)!
        list[User],
        validate_as_deferred(lambda: list[User]).transform(lambda x: x[1:]),
    ]
    bio: Annotated[
        datetime,
        validate_as(int)
        .transform(lambda x: x / 1_000_000)
        .validate_as(...),  # (8)!
    ]
  1. 将字符串小写。
  2. 将整数约束为大于零。

  3. 限制字符串匹配正则表达式模式。

  4. 你还可以使用较低级别的转换、约束和谓词方法。

  5. 使用 |& 运算符来组合步骤(例如逻辑或或与)。

  6. 调用 validate_as(...) 时使用 Ellipsis 作为第一个位置参数,这意味着 validate_as(<field type>) 。使用 validate_as(Any) 来接受任何类型。

  7. 对于递归类型,您可以在定义之前使用 validate_as_deferred 引用自身类型。

  8. 你可以在其他步骤之前或之后调用 validate_as() 进行预处理或后处理。

BeforeValidatorAfterValidatorWrapValidator 映射

validate_as 方法是一种更类型安全的方式来定义 BeforeValidatorAfterValidatorWrapValidator

from typing_extensions import Annotated

from pydantic.experimental.pipeline import transform, validate_as

# BeforeValidator
Annotated[int, validate_as(str).str_strip().validate_as(...)]  # (1)!
# AfterValidator
Annotated[int, transform(lambda x: x * 2)]  # (2)!
# WrapValidator
Annotated[
    int,
    validate_as(str)
    .str_strip()
    .validate_as(...)
    .transform(lambda x: x * 2),  # (3)!
]
  1. 在将字符串解析为整数之前,去除其空格。

  2. 将整数解析后乘以 2。

  3. 从字符串中删除空格,将其验证为整数,然后乘以 2。

备选模式

有许多可供选择的模式,具体取决于场景。仅作为示例,考虑上述的 UserInUserOut 模式:

from __future__ import annotations

from pydantic import BaseModel


class UserIn(BaseModel):
    favorite_number: int | str


class UserOut(BaseModel):
    favorite_number: int


def my_api(user: UserIn) -> UserOut:
    favorite_number = user.favorite_number
    if isinstance(favorite_number, str):
        favorite_number = int(user.favorite_number.strip())

    return UserOut(favorite_number=favorite_number)


assert my_api(UserIn(favorite_number=' 1 ')).favorite_number == 1

这个示例使用了简洁易懂的 Python 代码,可能比上述示例更容易理解、类型检查等。您选择的方法实际上应该取决于您的用例。您将不得不比较冗长性、性能、向用户返回有意义的错误等,以选择正确的模式。只是要注意不要滥用像管道 API 这样的高级模式,仅仅因为您可以。


本文总阅读量