资讯动态

Pydantic 入门指南:基于 Python 类型注解的数据校验实战

发布时间:2026/9/10 20:35:23 来源:尧图企业网站定制
Pydantic 入门指南基于 Python 类型注解的数据校验实战【免费下载链接】pydanticData validation using Python type hints项目地址: https://gitcode.com/GitHub_Trending/py/pydanticPydantic 是目前 Python 生态中使用最广泛的数据校验Data Validation库之一它的核心设计理念是用纯 Python 的类型注解type hints定义数据的形状再由 Pydantic 在运行时完成校验、转换与序列化。本文以官方文档入口 docs/index.md 为骨架结合仓库源码与测试带你从零掌握 Pydantic 的安装、BaseModel建模、宽松/严格模式、JSON Schema 生成、序列化与自定义校验等核心能力并理解其底层由 Rust 编写的pydantic-core校验引擎如何工作。一、为什么选择 Pydantic在进入代码之前先理解 Pydantic 被广泛采用的几个核心理由详见 docs/why.md由类型注解驱动Powered by type hints校验与序列化的 schema 完全由类型注解定义。现代 Python 开发者本就熟悉类型注解因此学习成本极低且能与 mypy、Pyright 等静态类型工具及 IDE 无缝集成。速度SpeedPydantic 的核心校验逻辑运行在 Rust 中。仓库中pydantic-core/目录下的 src/validators 与 src/serializers 即为其 Rust 实现这让 Pydantic 跻身 Python 最快的校验库之列。JSON Schema模型可自动生成 JSON Schema便于与 OpenAPI、前后端工具链集成。严格Strict与宽松Lax模式宽松模式下 Pydantic 会尽量把数据转换为正确类型如把字符串1转成整数严格模式下则不做任何转换输入必须与 schema 精确匹配。标准库类型支持dataclass、TypedDict、NamedTuple等标准库类型均可直接参与校验。高度可定制通过函数式校验器functional validators、序列化器与自定义类型协议可以按字段、按类型深度定制数据处理方式。安装 Pydantic 非常简单前提是 Python 3.10# pip pip install pydantic # uv uv add pydantic # condaconda-forge 频道 conda install pydantic -c conda-forge安装时建议同时安装可选依赖email邮箱校验基于 email-validator与timezoneIANA 时区数据库回退基于 tzdatapip install pydantic[email,timezone]依赖构成Pydantic 依赖pydantic-coreRust 核心校验逻辑、typing-extensionstyping 标准库回填、annotated-types配合Annotated使用的可复用约束类型以及typing-inspection运行时类型内省工具详见 docs/install.md。二、第一个模型用BaseModel定义数据结构Pydantic 最常用的方式是继承BaseModel定义一个模型类。类中的每个类型注解都对应一个字段fieldPydantic 会依据这些注解在实例化时自动完成校验。BaseModel定义于 pydantic/main.py其核心结构包含__pydantic_validator__pydantic-core的SchemaValidator负责校验输入__pydantic_serializer__pydantic-core的SchemaSerializer负责序列化输出model_configConfigDict配置项控制模型行为。来看官方首页 docs/index.md 中的经典示例from datetime import datetime from pydantic import BaseModel, PositiveInt class User(BaseModel): id: int # (1)! name: str John Doe # (2)! signup_ts: datetime | None # (3)! tastes: dict[str, PositiveInt] # (4)! external_data { id: 123, signup_ts: 2019-06-01 12:22, # (5)! tastes: { wine: 9, bcheese: 7, # (6)! cabbage: 1, # (7)! }, } user User(**external_data) # (8)! print(user.id) # (9)! # 123 print(user.model_dump()) # (10)! { id: 123, name: John Doe, signup_ts: datetime.datetime(2019, 6, 1, 12, 22), tastes: {wine: 9, cheese: 7, cabbage: 1}, } 逐行解读这个例子你可以直观感受由类型注解驱动的含义id: int只有注解、没有默认值表示该字段必填。字符串、字节串或浮点数会在可能的情况下被强制转换为整数否则抛出异常。name: str带有默认值John Doe因此非必填。signup_ts: datetime | None必填但允许传入NonePydantic 既能解析 Unix 时间戳整数如1496498400也能解析表示日期时间的字符串。tastes是键为字符串、值为正整数的字典。PositiveInt在 pydantic/types.py 中被定义为Annotated[int, annotated_types.Gt(0)]即大于 0 的整数是Annotatedannotated-types约束的语法糖。输入是 ISO 8601 格式的日期时间字符串Pydantic 会将其转换为datetime对象。字典键是bytesPydantic 会自动将其强制转换为字符串。字符串1会被强制转换为整数1。通过关键字参数把外部数据传入User构造实例。BaseModel.__init__内部会调用__pydantic_validator__.validate_python完成校验见 pydantic/main.py。字段可以通过属性直接访问。通过model_dump()把模型转换为字典。说明上述第 6、7 点展示的正是宽松模式下的数据强制转换coercion。如果开启严格模式这些输入都会直接报错。三、校验失败时的ValidationError当输入数据不符合 schema 时Pydantic 会抛出ValidationError并给出逐字段的错误明细。继续上面的例子from datetime import datetime from pydantic import BaseModel, PositiveInt, ValidationError class User(BaseModel): id: int name: str John Doe signup_ts: datetime | None tastes: dict[str, PositiveInt] external_data {id: not an int, tastes: {}} try: User(**external_data) except ValidationError as e: print(e.errors()) [ { type: int_parsing, loc: (id,), msg: Input should be a valid integer, unable to parse string as an integer, input: not an int, url: https://errors.pydantic.dev/2/v/int_parsing, }, { type: missing, loc: (signup_ts,), msg: Field required, input: {id: not an int, tastes: {}}, url: https://errors.pydantic.dev/2/v/missing, }, ] e.errors()返回的每条错误记录都包含type错误类型标识如int_parsing表示整数解析失败missing表示缺少必填字段loc出错位置字段路径元组msg人类可读的错误描述input原始输入值url指向错误码文档的链接便于快速查阅解释。注意两点id传入了not an int无法被解析为整数触发int_parsingsignup_ts缺失触发missing同时错误记录中会保留当时完整的输入字典方便调试。ValidationError实际来自pydantic_core在 pydantic/init.py 中被重导出为pydantic.ValidationError这样既保持了 API 的稳定性也方便 IDE 从 Pydantic 包内直接导入。四、核心 API校验、序列化与 JSON Schema4.1 校验入口除了直接实例化模型BaseModel还提供了类方法形式的校验入口model_validate(obj)校验任意 Python 对象字典、模型实例、支持属性访问的对象等。支持strict、extra、from_attributes、by_alias、by_name等参数底层调用__pydantic_validator__.validate_python见 pydantic/main.py。model_validate_json(json_data)一步完成JSON 解析 校验。由于 JSON 解析在 Rust 中实现速度很快且能在解析字符串的同时完成像datetime转换这类合理的数据转换见 pydantic/main.py。例如下面的严格模式示例来自 docs/why.mdfrom datetime import datetime from pydantic import BaseModel, ValidationError class Meeting(BaseModel): when: datetime where: bytes # 宽松模式自动转换 m Meeting.model_validate({when: 2020-01-01T12:00, where: home}) print(m) # whendatetime.datetime(2020, 1, 1, 12, 0) wherebhome # 严格模式类型必须精确匹配 try: Meeting.model_validate({when: 2020-01-01T12:00, where: home}, strictTrue) except ValidationError as e: print(e) 2 validation errors for Meeting when Input should be a valid datetime [typedatetime_type, input_value2020-01-01T12:00, input_typestr] where Input should be a valid bytes [typebytes_type, input_valuehome, input_typestr] # JSON 解析 校验一步到位 m_json Meeting.model_validate_json({when: 2020-01-01T12:00, where: home}) print(m_json) # whendatetime.datetime(2020, 1, 1, 12, 0) wherebhome4.2 序列化三件套Pydantic 提供三种序列化方式详见 docs/why.md 的 Serialization 小节与 docs/concepts/serialization.mdmodel_dump(modepython)转成由 Python 对象组成的字典如datetime保持为datetimemodel_dump(modejson)转成只含可 JSON 序列化类型的字典如datetime转为 ISO 字符串model_dump_json()直接输出 JSON 字符串。三种模式都支持通过include/exclude筛选字段以及exclude_unset排除未显式设置的字段、exclude_defaults排除等于默认值的字段、exclude_none排除None字段等过滤选项。model_dump与model_dump_json的完整参数签名可参考 pydantic/main.py 与 pydantic/main.py。示例from datetime import datetime from pydantic import BaseModel class Meeting(BaseModel): when: datetime where: bytes why: str No idea m Meeting(when2020-01-01T12:00, wherehome) print(m.model_dump(exclude_unsetTrue)) # {when: datetime.datetime(2020, 1, 1, 12, 0), where: bhome} print(m.model_dump(exclude{where}, modejson)) # {when: 2020-01-01T12:00:00, why: No idea} print(m.model_dump_json(exclude_defaultsTrue)) # {when:2020-01-01T12:00:00,where:home}4.3 JSON Schema 生成任何 Pydantic schema 都可以生成 JSON Schema这让 API 具备自描述能力并可直接与支持 JSON Schema 的工具链集成。Pydantic 兼容 JSON Schema 2020-12 规范因此也兼容 OpenAPI 3.1from datetime import datetime from pydantic import BaseModel class Address(BaseModel): street: str city: str zipcode: str class Meeting(BaseModel): when: datetime where: Address why: str No idea print(Meeting.model_json_schema()) { $defs: { Address: { properties: { street: {title: Street, type: string}, city: {title: City, type: string}, zipcode: {title: Zipcode, type: string}, }, required: [street, city, zipcode], title: Address, type: object, } }, properties: { when: {format: date-time, title: When, type: string}, where: {$ref: #/$defs/Address}, why: {default: No idea, title: Why, type: string}, }, required: [when, where], title: Meeting, type: object, } 可以看到嵌套模型Address被提取到$defs中并通过$ref引用字段类型、默认值与必填信息都完整地体现在 schema 中。生成入口为BaseModel.model_json_schema()见 pydantic/main.py更完整的自定义能力可参考 docs/concepts/json_schema.md。五、不止于BaseModel四种建模方式Pydantic 提供四种方式创建 schema 并执行校验与序列化详见 docs/why.md 的 Dataclasses, TypedDicts, and more 小节BaseModelPydantic 自带的模型基类提供大量实例方法model_dump、model_validate等。参见 docs/concepts/models.md。Pydantic dataclasses对标准库dataclass的包装在保持 dataclass 体验的同时叠加校验能力。参见 docs/concepts/dataclasses.md。TypeAdapter把任意类型适配为可校验、可序列化的对象——不仅限于模型。例如可以用它校验TypedDict、NamedTuple甚至单个int或timedelta。参见 docs/api/type_adapter.md。validate_call装饰器在调用普通函数时对参数执行校验。参见 docs/concepts/validation_decorator.md。其中TypeAdapter特别适合只想校验一个数据结构、不想定义模型的场景。例如用TypedDict定义 schemafrom datetime import datetime from typing_extensions import NotRequired, TypedDict from pydantic import TypeAdapter class Meeting(TypedDict): when: datetime where: bytes why: NotRequired[str] meeting_adapter TypeAdapter(Meeting) # 校验 Python 对象 m meeting_adapter.validate_python({when: 2020-01-01T12:00, where: home}) print(m) # {when: datetime.datetime(2020, 1, 1, 12, 0), where: bhome} # 序列化为 Python 对象 / JSON meeting_adapter.dump_python(m, exclude{where}) # 生成 JSON Schema print(meeting_adapter.json_schema()) { properties: { when: {format: date-time, title: When, type: string}, where: {format: binary, title: Where, type: string}, why: {title: Why, type: string}, }, required: [when, where], title: Meeting, type: object, } TypeAdapter同样支持validate_json直接校验 JSON与dump_json输出 JSON 字符串。它的定义位于 pydantic/type_adapter.py并从 pydantic/init.py 导出。六、自定义校验wrap validators 与约束类型6.1 用Annotated表达约束得益于annotated-types包你可以在不改动字段类型的情况下表达约束。最典型的例子就是首页示例中的PositiveIntpydantic/types.pyPositiveInt Annotated[int, annotated_types.Gt(0)]类似的约束类型还包括NegativeIntLt(0)、NonNegativeIntGe(0)、NonPositiveIntLe(0)等全部定义于 pydantic/types.py。你也可以直接写from typing import Annotated from annotated_types import Gt, MultipleOf from pydantic import BaseModel class Fruit(BaseModel): name: str weight: Annotated[float, Gt(0), MultipleOf(0.5)]6.2 wrap validatorsPydantic V2 最强大的自定义方式wrap validators 是 Pydantic V2 引入的能力你可以在字段校验之前或之后插入自定义逻辑并且可以显式调用内置的校验 handler。示例来自 docs/why.mdfrom datetime import datetime, timezone from typing import Any from pydantic_core.core_schema import ValidatorFunctionWrapHandler from pydantic import BaseModel, field_validator class Meeting(BaseModel): when: datetime field_validator(when, modewrap) def when_now(cls, input_value: Any, handler: ValidatorFunctionWrapHandler) - datetime: if input_value now: return datetime.now() when handler(input_value) # 在此应用场景中我们已知无时区的 naive datetime 表示 UTC if when.tzinfo is None: when when.replace(tzinfotimezone.utc) return when print(Meeting(when2020-01-01T12:0001:00)) # whendatetime.datetime(2020, 1, 1, 12, 0, tzinfoTzInfo(3600)) print(Meeting(whennow)) # whendatetime.datetime(2032, 1, 2, 3, 4, 5, 6) print(Meeting(when2020-01-01T12:00)) # whendatetime.datetime(2020, 1, 1, 12, 0, tzinfodatetime.timezone.utc)要点解读modewrap表示该校验器包裹内置校验逻辑handler(input_value)会继续执行默认校验输入now被替换为当前时间其余输入先交给handler处理再补充时区信息相关装饰器field_validator、model_validator等从 pydantic/functional_validators.py 导出更全面的自定义能力可参考 docs/concepts/validators.md 与 docs/concepts/serialization.md。七、性能与生态7.1 性能从何而来Pydantic 的性能来自分层架构校验与 JSON 解析的核心逻辑全部用 Rust 编写在pydantic-core中仓库对应目录为 pydantic-core/srcPython 层的pydantic负责构建 schema、解析类型注解并把控制权交给 Rust 引擎。官方文档给出了一个可复现的基准示例见 docs/why.md 的 Performance 小节在解析 JSON 并校验 URL 的场景中Pydantic 比手写的纯 Python 代码快约 3.45 倍。提示性能数据随机器与 Python 版本变化建议在自己的环境中运行 pydantic-core/benches/main.rs 或仓库 tests/benchmarks 下的基准测试验证。7.2 谁在使用 PydanticPydantic 已深度融入 Python 生态PyPI 上有大量第三方包以它为依赖包括 FastAPI、Hugging Face 生态、Django Ninja、SQLModel、LangChain 等常见框架与工具。围绕 Pydantic其团队还构建了观测平台 Pydantic Logfire提供对校验流程的原生追踪与生产环境调试能力参见 docs/integrations/logfire.md。更完整的依赖方列表可查看仓库内的 docs/pydantic_people.md 与 docs/plugins/orgs.toml。八、继续深入仓库资源导览本仓库是一个包含完整 Python 实现pydantic/、Rust 核心pydantic-core/、文档docs/与测试tests/的完整代码库你可以按以下路径继续探索关注点建议阅读模型核心实现pydantic/main.pyBaseModel定义类型与约束pydantic/types.pyPositiveInt等约束类型函数式校验器pydantic/functional_validators.py任意类型适配pydantic/type_adapter.pyRust 校验引擎pydantic-core/src/validators测试示例tests/test_main.py、tests/test_validators.py概念文档docs/concepts/models.md、docs/concepts/validators.md、docs/concepts/serialization.md小结通过本文你应该已经掌握了 Pydantic 的核心使用范式用类型注解定义模型、用BaseModel与TypeAdapter完成校验与序列化、用ValidationError定位错误、用Annotated与 wrap validators 实现自定义约束。它的设计哲学——用你早已熟悉的 Python 类型注解定义数据应该长什么样——使得从数据校验到 API 文档生成、再到 JSON Schema 输出都能以最小的代码量落地。下一步建议直接阅读 docs/concepts/models.md 深入理解模型行为并结合仓库 tests 下的测试用例验证你的理解。【免费下载链接】pydanticData validation using Python type hints项目地址: https://gitcode.com/GitHub_Trending/py/pydantic创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价