Rust又立功了!Pydantic V2 的性能提升显著,速度比 V1 快 5 到 50 倍

968 阅读3分钟

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 时,它可以根据请求参数的内容自动选择正确的数据模型进行验证和解析。

基础用法

在实际开发中,“判别联合类型”可以用于以下场景:

  1. 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"
          }
      }
      
  2. 日志和事件系统 如果你的系统需要处理不同类型的日志或事件,“判别联合类型”可以根据事件的 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 模型即可,而无需手动判断和解析每种事件类型。

  3. 多态配置加载 在一些配置场景中,不同的组件可能需要不同的配置结构。通过判别联合类型,可以轻松实现多态配置。例如:

    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 倍,在处理大规模数据时效率更高。