跳转到内容

类型适配器

你可能有一些不是 BaseModel 的类型,但你希望用它们来验证数据。或者,你可能想验证一个 list[SomeModel],或将其转储为 JSON。

API 文档

pydantic.type_adapter.TypeAdapter

对于类似这样的用例,Pydantic 提供了 TypeAdapter,它可用于类型验证、序列化和 JSON schema 生成,而无需创建 BaseModel

一个 TypeAdapter 实例为那些没有类似方法(例如 dataclasses、原始类型等)的类型,暴露了 BaseModel 实例方法的部分功能。

from typing_extensions import TypedDict

from pydantic import TypeAdapter, ValidationError


class User(TypedDict):
    name: str
    id: int


user_list_adapter = TypeAdapter(list[User])
user_list = user_list_adapter.validate_python([{'name': 'Fred', 'id': '3'}])
print(repr(user_list))
#> [{'name': 'Fred', 'id': 3}]

try:
    user_list_adapter.validate_python(
        [{'name': 'Fred', 'id': 'wrong', 'other': 'no'}]
    )
except ValidationError as e:
    print(e)
    """
    1 validation error for list[User]
    0.id
      Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='wrong', input_type=str]
    """

print(repr(user_list_adapter.dump_json(user_list)))
#> b'[{"name":"Fred","id":3}]'
from typing import TypedDict

from pydantic import TypeAdapter, ValidationError


class User(TypedDict):
    name: str
    id: int


user_list_adapter = TypeAdapter(list[User])
user_list = user_list_adapter.validate_python([{'name': 'Fred', 'id': '3'}])
print(repr(user_list))
#> [{'name': 'Fred', 'id': 3}]

try:
    user_list_adapter.validate_python(
        [{'name': 'Fred', 'id': 'wrong', 'other': 'no'}]
    )
except ValidationError as e:
    print(e)
    """
    1 validation error for list[User]
    0.id
      Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='wrong', input_type=str]
    """

print(repr(user_list_adapter.dump_json(user_list)))
#> b'[{"name":"Fred","id":3}]'

dump_json 返回 bytes

TypeAdapterdump_json 方法返回一个 bytes 对象,这与 BaseModel 对应的 model_dump_json 方法返回 str 不同。造成这种差异的原因是,在 V1 版本中,模型转储返回的是 str 类型,因此为了向后兼容,V2 保留了这一行为。对于 BaseModel 的情况,bytes 被强制转换为 str 类型,但通常期望的最终类型是 bytes。因此,对于 V2 中新的 TypeAdapter 类,返回类型就是 bytes,如果需要,可以轻松地将其强制转换为 str 类型。

注意

尽管在某些用例上与 RootModel 有重叠,但 TypeAdapter 不应该用作类型注解来指定 BaseModel 的字段等。

将数据解析为指定类型

TypeAdapter 可用于以更灵活的方式应用解析逻辑来填充 Pydantic 模型。此函数的行为类似于 BaseModel.model_validate,但适用于任意与 Pydantic 兼容的类型。

当你想将结果解析为非 BaseModel 直接子类的类型时,这尤其有用。例如:

from pydantic import BaseModel, TypeAdapter


class Item(BaseModel):
    id: int
    name: str


# `item_data` could come from an API call, eg., via something like:
# item_data = requests.get('https://my-api.com/items').json()
item_data = [{'id': 1, 'name': 'My Item'}]

items = TypeAdapter(list[Item]).validate_python(item_data)
print(items)
#> [Item(id=1, name='My Item')]

TypeAdapter 能够将数据解析为 Pydantic 可作为 BaseModel 字段处理的任何类型。

性能考量

在创建 TypeAdapter 实例时,必须分析提供的类型并将其转换为 pydantic-core schema。这会带来一些不可忽略的开销,因此建议对给定类型只创建一个 TypeAdapter,并在循环或其他对性能敏感的代码中复用它。

重建 TypeAdapter 的 schema

在 v2.10+ 版本中,TypeAdapter 支持延迟 schema 构建和手动重建。这对于以下情况很有帮助:

  • 带有前向引用的类型
  • 核心 schema 构建成本较高的类型

当你用一个类型初始化 TypeAdapter 时,Pydantic 会分析该类型并为其创建一个核心 schema。这个核心 schema 包含了验证和序列化该类型数据所需的信息。有关核心 schema 的更多信息,请参阅架构文档

如果在初始化 TypeAdapter 时将 defer_build 设置为 True,Pydantic 会将核心 schema 的构建推迟到第一次需要它时(用于验证或序列化)进行。

为了手动触发核心 schema 的构建,你可以在 TypeAdapter 实例上调用 rebuild 方法。

from pydantic import ConfigDict, TypeAdapter

ta = TypeAdapter('MyInt', config=ConfigDict(defer_build=True))

# some time later, the forward reference is defined
MyInt = int

ta.rebuild()
assert ta.validate_python(1) == 1