Pydantic 是一个用于数据验证和配置管理的 Python 库,最近发布了 2.0 版本,带来了许多新功能和性能提升。Pydantic 2 的核心由 Rust 编写,相比 1.x 版本,性能提升了 5 至 50 倍,在处理大规模数据时效率更高。
以下是 Pydantic 2 的主要更新和特点:
新功能
支持 Python 3.13
Pydantic 2 正式兼容 Python 3.13,并推出了基于 Cython 的轮子包,提高了与该版本的适配性。
函数参数验证
新增 @validate_call 装饰器,可以对函数参数进行验证,简化了代码中的验证逻辑。例如:
from pydantic import validate_call
from pydantic.types import conint
@validate_call
def echo_hello(n_times: conint(gt=0, lt=11), name: str, loud: bool):
# 函数实现
判别联合类型
Pydantic 2 引入了“判别联合类型”的功能,可以根据字段的特定值决定使用哪个模型。这种功能在需要动态处理不同结构的数据时非常有用,尤其是在构建 API 时,它可以根据请求参数的内容自动选择正确的数据模型进行验证和解析。
基础用法
在实际开发中,“判别联合类型”可以用于以下场景:
-
FastAPI 的动态请求体验证 在 FastAPI 中,可以根据请求的
d_type字段动态验证请求体的数据结构。例如(注:感觉像Java的依赖注入概念)from fastapi import FastAPI from typing import Union from pydantic import BaseModel, Field from typing import Literal, List app = FastAPI() class TextMessage(BaseModel): type: Literal["text"] content: str class ImageMessage(BaseModel): type: Literal["image"] url: str width: int height: int class Message(BaseModel): message: Union[TextMessage, ImageMessage] = Field(discriminator="type") @app.post("/messages/") async def handle_message(message: Message): if message.message.type == "text": return {"message_type": "Text Message", "content": message.message.content} elif message.message.type == "image": return { "message_type": "Image Message", "image_info": { "url": message.message.url, "dimensions": f"{message.message.width}x{message.message.height}", }, }上述代码可以根据请求体中的
type字段,自动选择对应的模型进行验证。例如:-
请求体为文本消息时:
{ "message": { "type": "text", "content": "Hello, world!" } }返回结果:
{ "message_type": "Text Message", "content": "Hello, world!" } -
请求体为图片消息时:
{ "message": { "type": "image", "url": "http://example.com/image.png", "width": 800, "height": 600 } }返回结果:
{ "message_type": "Image Message", "image_info": { "url": "http://example.com/image.png", "dimensions": "800x600" } }
-
-
日志和事件系统 如果你的系统需要处理不同类型的日志或事件,“判别联合类型”可以根据事件的
type字段,自动选择正确的事件模型。例如:class LoginEvent(BaseModel): event_type: Literal["login"] user_id: int timestamp: str class PurchaseEvent(BaseModel): event_type: Literal["purchase"] user_id: int item_id: int amount: float class SystemEvent(BaseModel): event: Union[LoginEvent, PurchaseEvent] = Field(discriminator="event_type")这样在解析事件日志时,只需处理顶层
SystemEvent模型即可,而无需手动判断和解析每种事件类型。 -
多态配置加载 在一些配置场景中,不同的组件可能需要不同的配置结构。通过判别联合类型,可以轻松实现多态配置。例如:
class DatabaseConfig(BaseModel): type: Literal["database"] host: str port: int username: str password: str class CacheConfig(BaseModel): type: Literal["cache"] backend: str ttl: int class AppConfig(BaseModel): config: Union[DatabaseConfig, CacheConfig] = Field(discriminator="type")这样加载配置文件时可以直接解析出正确的配置类型:
{ "config": { "type": "database", "host": "localhost", "port": 5432, "username": "admin", "password": "secret" } }
注解验证器
支持在字段上直接定义验证器,而无需绑定到模型,方便在多个模块间共享验证逻辑。例如:
from typing_extensions import Annotated
from pydantic.functional_validators import AfterValidator
def validate_positive(v: int):
assert v > 0
PositiveNumber = Annotated[int, AfterValidator(validate_positive)]
TypeAdapter 类
TypeAdapter 类允许在不创建 BaseModel 的情况下对数据进行验证和转换,非常适合单元测试。例如:
from pydantic import TypeAdapter
ta = TypeAdapter(PositiveNumber)
result = ta.validate_python(10) # 验证通过
自定义序列化
支持自定义字段的导出格式,例如可以将 datetime 对象格式化为字符串:
from datetime import datetime
from pydantic import BaseModel, field_serializer
class Event(BaseModel):
event_time: datetime
@field_serializer("event_time")
def serialize_event_time(v) -> str:
return v.strftime("%Y-%m-%d %H:%M:%S")
性能提升
Pydantic 2 的核心由 Rust 编写,相比 1.x 版本,性能提升了 5 至 50 倍,在处理大规模数据时效率更高。