跳到主要内容

05. Types

一般来说,使用标准的类型就足以体验顺畅的校验和解析功能了。不过 Pydantic 也补充提供了一系列有用的类型。

The following sections describe the types supported by Pydantic.

类型转换

During validation, Pydantic can coerce data into expected types.

There are two modes of coercion: strict and lax. See Conversion Table for more details on how Pydantic converts data in both strict and lax modes.

See Strict mode and Strict Types for details on enabling strict coercion.

Strict Types 严格类型

五种严格类型,即五种基础类型的严格模式

自定义类型

You can also define your own custom data types. There are several ways to achieve it.

这里只摘录了 Annotated,其他的方法详见官方文档

使用 Annotated 构建

PEP 593 引入了 Annotated 语法,在不改变类型检查器对 types 的解释方式的前提下,将运行时元数据添加到 types 中。Pydantic 利用这一点,允许你创建类型,在类型检查器看来与原始类型完全相同,但可以添加验证、以不同方式序列化等功能。

For example, to create a type representing a positive int:

from typing import Annotated
from pydantic import Field, TypeAdapter, ValidationError

PositiveInt = Annotated[int, Field(gt=0)]

ta = TypeAdapter(PositiveInt)

print(ta.validate_python(1))
#> 1

try:
ta.validate_python(-1)
except ValidationError as exc:
print(exc)
"""
1 validation error for constrained-int
Input should be greater than 0 [type=greater_than, input_value=-1, input_type=int]
"""

Note that you can also use constraints from annotated-types to make this Pydantic-agnostic:

from annotated_types import Gt
from typing_extensions import Annotated

from pydantic import TypeAdapter, ValidationError

PositiveInt = Annotated[int, Gt(0)]

ta = TypeAdapter(PositiveInt)

# ...

添加验证方法与序列化方法

You can add or override validation, serialization, and JSON schemas to an arbitrary type using the markers that Pydantic exports:

from typing_extensions import Annotated

from pydantic import (
AfterValidator,
PlainSerializer,
TypeAdapter,
WithJsonSchema,
)

TruncatedFloat = Annotated[
float,
AfterValidator(lambda x: round(x, 1)),
PlainSerializer(lambda x: f'{x:e}', return_type=str),
WithJsonSchema({'type': 'string'}, mode='serialization'),
]


ta = TypeAdapter(TruncatedFloat)

input = 1.02345
assert input != 1.0

assert ta.validate_python(input) == 1.0

assert ta.dump_json(input) == b'"1.0e+00"'

assert ta.json_schema(mode='validation') == {'type': 'number'}
assert ta.json_schema(mode='serialization') == {'type': 'string'}
  • AfterValidator:(在默认验证逻辑之后额外添加的)验证逻辑
  • PlainSerializer:序列化逻辑
  • WithJsonSchema:JSON schema 的解析逻辑

Generics 泛型

Annotate 还可以用在泛型上

You can use type variables within Annotated to make re-usable modifications to types:

from typing import Any, List, Sequence, TypeVar

from annotated_types import Gt, Len
from typing_extensions import Annotated

from pydantic import ValidationError
from pydantic.type_adapter import TypeAdapter

SequenceType = TypeVar('SequenceType', bound=Sequence[Any])
ShortSequence = Annotated[SequenceType, Len(max_length=10)]

ta = TypeAdapter(ShortSequence[List[int]])

v = ta.validate_python([1, 2, 3, 4, 5])
assert v == [1, 2, 3, 4, 5]

try:
ta.validate_python([1] * 100)
except ValidationError as exc:
print(exc)
"""
1 validation error for list[int]
List should have at most 10 items after validation, not 100 [type=too_long, input_value=[1, 1, 1, 1, 1, 1, 1, 1, ... 1, 1, 1, 1, 1, 1, 1, 1], input_type=list]
"""

T = TypeVar('T') # or a bound=SupportGt
PositiveList = List[Annotated[T, Gt(0)]]

ta = TypeAdapter(PositiveList[float])

v = ta.validate_python([1])
assert type(v[0]) is float

try:
ta.validate_python([-1])
except ValidationError as exc:
print(exc)
"""
1 validation error for list[constrained-float]
0
Input should be greater than 0 [type=greater_than, input_value=-1, input_type=int]
"""