如果要在 Python 生态里选一个"无处不在但不显眼"的库,Pydantic 当仁不让:FastAPI 靠它做请求验证,LangChain 靠它约束模型输出,OpenAI SDK 靠它定义工具参数。官方定位一句话:基于 Python 类型提示的数据验证库。它在 GitHub 有约 24k Star,MIT 协议,仓库地址为 pydantic/pydantic。本文从安装与基本用法讲起,覆盖模型定义、校验器、序列化与高级特性,最后给出性能与选型建议。
1、项目概述
Pydantic 解决的问题是:外部数据(JSON 请求、环境变量、配置文件、LLM 输出)进入 Python 程序时的解析、校验与类型转换。传统做法是手写一堆 if not isinstance(...) 判断,Pydantic 把这一切交给类型注解——声明即校验,错误信息自动带字段路径。
它的核心特性包括:
- 使用纯 Python 类型提示定义数据模型
- 校验速度快,V2 核心用 Rust 编写
- 与 IDE、linter 深度兼容,补全友好
- 支持 JSON Schema 生成与双向序列化
- 内置 V1 兼容层(
from pydantic import v1)
安装命令:
pip install -U pydantic
也可以用 conda 安装:conda install pydantic -c conda-forge。V2 是一次彻底重写,校验性能比 V1 提升约 5 到 50 倍,同时保留了 V1 的兼容导入路径,老项目可以平滑迁移。
2、模型定义与校验
一切从 BaseModel 开始,下面是 README 中的官方示例:
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str = 'John Doe'
signup_ts: Optional[datetime] = None
friends: list[int] = []
external_data = {'id': '123', 'signup_ts': '2017-06-01 12:22', 'friends': [1, '2', b'3']}
user = User(**external_data)
print(user)
注意 external_data 里传入的原始值有多"脏":id 是字符串,friends 混着 int、str、bytes。Pydantic 全部正确转换——user.id 变成 int 类型的 123,时间字符串解析为 datetime 对象。转换失败时会抛出 ValidationError,错误信息精确到每个字段和失败原因,比如 id: Input should be a valid integer。
默认值的声明就是普通的 Python 语法:name: str = 'John Doe' 表示缺省时用默认值。字段类型可以用所有标准注解写法,Optional[X]、list[X]、dict[str, X]、联合类型都开箱即用。
3、校验器与字段约束
当内置类型转换不够用时,field_validator 让你挂载自定义逻辑:
from pydantic import BaseModel, field_validator
class Account(BaseModel):
username: str
age: int
@field_validator('username')
@classmethod
def check_username(cls, v: str) -> str:
if not v.isalnum():
raise ValueError('must be alphanumeric')
return v
校验器在标准类型转换之后执行,抛 ValueError 或 AssertionError 都会被收集进 ValidationError。数值与字符串的常见约束则不需要写代码,Field(ge=0, le=150) 一行就能限制范围,Field(min_length=3, max_length=20) 管长度,还有 Field(default_factory=list) 避免可变默认值的坑。模型级别的跨字段校验用 model_validator,例如校验"折扣价必须低于原价"这类规则。
4、序列化与配置管理
数据进得来也要出得去。model_dump() 输出 Python 字典,model_dump_json() 直接输出 JSON 字符串,model_dump(exclude={'password'}) 可以在序列化时剔除敏感字段。反向的 model_validate() 从字典构造模型,model_validate_json() 直接解析 JSON 字符串且跳过中间 dict,性能更好。配套的 model_json_schema() 生成标准 JSON Schema,这是 FastAPI 文档和 LLM 结构化输出的基础。
工程里另一个高频场景是环境变量配置,pydantic-settings 包(需单独安装 pip install pydantic-settings)提供 BaseSettings:
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
database_url: str
debug: bool = False
settings = Settings()
实例化时自动读取同名环境变量(含 .env 文件),类型校验同步完成。数据库连接串少配一个字符,启动时立刻报错,而不是等到第一次查询才炸,这是配置管理正确的打开方式。
5、性能与生态
V2 的性能提升来自核心校验逻辑用 Rust 重写(pydantic-core),官方基准显示常见场景比 V1 快 5 到 50 倍,内存占用也显著下降。对性能仍有极致要求的路径,可以用 TypeAdapter 校验单个值而不定义模型,或开启序列化的加速路径。
生态方面值得了解几件事:
- FastAPI 的请求与响应验证直接构建在 Pydantic 之上
- LangChain 与各大 LLM SDK 用它约束结构化输出
from pydantic import v1兼容层让老代码渐进迁移model_construct()跳过校验构造对象,仅用于可信数据
迁移 V2 时的主要破坏点:@validator 换成 field_validator、.dict() 与 .json() 换成 model_dump() 系列、Config 类换成 model_config 字典。官方提供了 bump-pydantic 自动化迁移工具。
6、总结
Pydantic 把"类型注解"从文档变成了运行时的安全网,任何与外部数据打交道的 Python 程序都能从中受益,它也确实成了 AI 应用时代事实上的数据层标准。对于新项目,建议直接用 V2 并全面以 BaseModel 与 BaseSettings 管理数据边界;对于 V1 老项目,建议先用兼容层锁行为,再借 bump-pydantic 分模块迁移。深入学习推荐官方文档,其校验器与序列化两章值得精读。

