环企首页
Pydantic 详解
Pydantic 是 Python 中最流行的数据验证和设置管理库,它利用 Python 类型注解在运行时对数据进行验证,并提供清晰的错误信息。
1. 核心概念
- 数据验证:自动检查数据是否符合指定的类型和约束
- 类型转换:尽可能将输入数据转换为正确的类型
- 序列化:轻松将模型转换为字典或 JSON 格式
- IDE 友好:基于类型注解,提供完美的代码补全和支持
2. 基础用法
最简单的例子
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
email: str
# 自动验证和类型转换
user = User(name="张三", age="25", email="zhang@example.com")
print(user) # name='张三' age=25 email='zhang@example.com'
print(user.age + 1) # 26 (被正确转换为 int)
# 无效数据会引发错误
try:
user2 = User(name="李四", age="not a number", email="li@example.com")
except ValidationError as e:
print(e)
字段的默认值和可选字段
from pydantic import BaseModel
from typing import Optional
class Config(BaseModel):
name: str = "默认配置" # 默认值
debug: bool = False # 默认 False
timeout: Optional[int] = None # 可选字段,默认 None
tags: list[str] = [] # 空列表作为默认值
config = Config()
print(config.name) # "默认配置"
print(config.debug) # False
config2 = Config(name="自定义", debug=True)
print(config2.name) # "自定义"
3. 高级验证
使用 Field 添加验证规则
from pydantic import BaseModel, Field, ValidationError
from typing import Optional
class Product(BaseModel):
name: str = Field(..., min_length=1, max_length=100) # ... 表示必填
price: float = Field(..., gt=0, le=9999.99) # 大于0,小于等于9999.99
quantity: int = Field(default=0, ge=0) # 大于等于0
description: Optional[str] = Field(None, max_length=500)
try:
product = Product(name="", price=-10) # 验证失败
except ValidationError as e:
print(e.errors())
自定义验证器
from pydantic import BaseModel, field_validator, model_validator
class Order(BaseModel):
items: list[str]
quantities: list[int]
discount: float = 0.0
# 单个字段验证
@field_validator('discount')
@classmethod
def validate_discount(cls, v: float) -> float:
if not 0 <= v <= 1:
raise ValueError('折扣必须在0-1之间')
return v
# 多个字段验证
@model_validator(mode='after')
def check_lengths(self) -> 'Order':
if len(self.items) != len(self.quantities):
raise ValueError('商品列表和数量列表长度必须相同')
return self
order = Order(items=["book"], quantities=[2, 3]) # 长度不匹配 -> 报错
使用 ConfigDict 配置模型行为
from pydantic import BaseModel, ConfigDict
class User(BaseModel):
model_config = ConfigDict(
extra='forbid', # 禁止额外字段
frozen=True, # 不可变对象
title='UserModel' # 模型标题
)
user = User(name="张三")
# user.name = "李四" # 如果 frozen=True,这会报错
4. 嵌套模型
from pydantic import BaseModel
from typing import List
class Address(BaseModel):
street: str
city: str
zipcode: str
class User(BaseModel):
name: str
age: int
address: Address # 嵌套模型
tags: List[str] = [] # 列表类型
# 可以传字典,Pydantic 会自动转换
user_data = {
"name": "张三",
"age": 25,
"address": {
"street": "中关村大街1号",
"city": "北京",
"zipcode": "100080"
},
"tags": ["developer", "python"]
}
user = User(**user_data)
print(user.address.city) # 北京
5. 序列化和反序列化
from pydantic import BaseModel
from datetime import datetime
class Event(BaseModel):
name: str
timestamp: datetime
event = Event(name="会议", timestamp="2024-01-15T10:30:00")
# 转换为字典
event_dict = event.model_dump()
print(event_dict) # {'name': '会议', 'timestamp': datetime.datetime(2024, 1, 15, 10, 30)}
# 转换为 JSON
event_json = event.model_dump_json()
print(event_json) # {"name":"会议","timestamp":"2024-01-15T10:30:00"}
# 从字典反序列化
event2 = Event.model_validate(event_dict)
# 从 JSON 反序列化
event3 = Event.model_validate_json(event_json)
6. 在 LangGraph 中的实际应用
你在 LangGraph 中可能会看到这样的用法:
from typing import Annotated, List
from langgraph.graph.message import add_messages
from pydantic import BaseModel
# 定义状态模型
class MessagesState(BaseModel):
messages: Annotated[List[AnyMessage], add_messages]
user_name: str = "anonymous"
session_id: str = ""
# 可以添加验证规则
current_step: str = Field(default="start", pattern="^(start|process|end)$")
# 使用模型
state = MessagesState(
messages=[HumanMessage(content="你好")],
session_id="session_123"
)
print(state.current_step) # "start"
7. 常用 Field 参数
| 参数 | 说明 | 示例 |
|---|---|---|
default |
默认值 | Field(default=0) |
... (Ellipsis) |
必填字段 | Field(...) |
gt |
大于 | Field(gt=0) |
ge |
大于等于 | Field(ge=0) |
lt |
小于 | Field(lt=100) |
le |
小于等于 | Field(le=100) |
min_length |
最小长度 | Field(min_length=1) |
max_length |
最大长度 | Field(max_length=100) |
pattern |
正则表达式 | Field(pattern=r'^[A-Z]+$') |
description |
字段描述 | Field(description="用户名") |
8. 性能优化:使用 @dataclass 装饰器
对于简单场景,可以使用性能更好的 @dataclass 装饰器:
from pydantic.dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
@field_validator('x')
@classmethod
def validate_x(cls, v: float) -> float:
if v < 0:
raise ValueError('x 不能为负数')
return v
point = Point(x=10, y=20)
9. 与类型注解配合
from typing import Union, Literal, Optional
from datetime import date
class Task(BaseModel):
id: int
title: str
status: Literal['pending', 'in_progress', 'completed'] # 字面量类型
due_date: Union[date, None] = None # 联合类型
priority: Optional[int] = None # 可选类型
10. Pydantic vs 普通类
| 特性 | 普通 Python 类 | Pydantic 模型 |
|---|---|---|
| 类型检查 | ❌ 不在运行时检查 | ✅ 自动验证 |
| 类型转换 | ❌ 手动处理 | ✅ 自动转换 |
| 序列化 | ❌ 需要手动实现 | ✅ 内置方法 |
| 验证规则 | ❌ 手动写 if | ✅ 声明式 |
| JSON 支持 | ❌ 需要库 | ✅ 原生支持 |
| 性能 | 较快 | 略慢(含验证开销) |
💎 总结
- Pydantic 的核心价值:利用 Python 类型注解,在运行时提供数据验证和类型转换
- 主要使用场景:配置管理、API 请求/响应验证、数据序列化、LangGraph 状态管理
- 最佳实践:始终为关键数据模型使用 Pydantic,利用内置验证器而非手动写 if 语句
- 版本注意:Pydantic v2 与 v1 有较大变化,你当前使用的是 v2(从语法看)
如果你使用 LangGraph,Pydantic 帮助你确保状态模型的一致性和安全性,特别是在复杂的 Agent 工作流中。