ai
  • index
  • 1.欢迎来到LlamaIndex
  • 2.高级概念
  • 3.安装与设置
  • 4.入门教程(使用OpenAI)
  • 5.入门教程(使用本地LLMs)
  • 6.构建一个LLM应用
  • 7.使用LLMs
  • pydantic
  • asyncio
  • apikey
  • 8.RAG简介
  • 9.加载数据
  • 10.索引
  • 11.存储
  • 12.查询
  • weaviate
  • Cohere
  • warnings
  • WeaviateStart
  • spacy
  • 使用LlamaIndex构建全栈Web应用指南
  • back2
  • back4
  • front2
  • front4
  • front6
  • front8
  • llamaindex_backend
  • llamaindex_frontend
  • 1. 核心概念
    • 1.1 基本模型
    • 1.2 主要特点
  • 2. 基本用法
    • 2.1 模型实例化
    • 2.2 模型导出
    • 2.3 验证错误处理
  • 3. 高级特性
    • 3.1 字段类型
    • 3.2 验证器
    • 3.3 模型配置
    • 3.4 嵌套模型
  • 4. 实用功能
    • 4.1 动态模型创建
    • 4.2 数据解析
    • 4.3 与 JSON Schema 集成
  • 5. 性能优化
    • 5.1 使用严格模式
    • 5.2 自定义类型
  • 6. 与 FastAPI 集成
  • 7. 最佳实践
  • 8. 常见问题
    • 8.1 循环引用
    • 8.2 自定义 JSON 编码
  • 9. 版本变化
  • 总结

Pydantic 是一个 Python 库,主要用于数据验证和设置管理,使用 Python 类型注解。它在 FastAPI 等现代 Python 框架中被广泛使用,因其强大的数据验证能力和简洁的 API 设计而备受开发者青睐。

1. 核心概念 #

1.1 基本模型 #

Pydantic 的核心是模型(Model),通过继承 pydantic.BaseModel 来定义数据结构。模型使用 Python 类型注解来定义字段类型,Pydantic 会自动验证输入数据是否符合这些类型定义,并进行必要的类型转换。

# 导入必要的模块
from pydantic import BaseModel
from datetime import datetime

# 定义一个用户模型,继承自BaseModel
class User(BaseModel):
    # 用户ID,必填字段,整数类型
    id: int
    # 用户名,可选字段,字符串类型,默认值为"John Doe"
    name: str = "John Doe"
    # 注册时间,可选字段,datetime类型或None,默认值为None
    signup_ts: datetime | None = None
    # 朋友列表,可选字段,整数列表,默认值为空列表
    friends: list[int] = []

# 测试代码
if __name__ == "__main__":
    # 创建用户实例
    user = User(id=1, name="Alice")
    print(f"用户: {user.name}, ID: {user.id}")
    print(f"朋友列表: {user.friends}")

1.2 主要特点 #

Pydantic 的主要特点包括类型注解、自动验证、数据转换、易用性和高性能。这些特点使得 Pydantic 成为现代 Python 开发中数据验证的首选工具。

  1. 类型注解:使用 Python 类型提示
  2. 自动验证:自动验证输入数据是否符合类型注解
  3. 数据转换:自动将输入数据转换为正确的类型
  4. 易于使用:与 Python 生态系统无缝集成
  5. 高性能:核心逻辑用 Rust 实现

2. 基本用法 #

2.1 模型实例化 #

模型实例化是 Pydantic 的基本用法,可以从字典、JSON 数据或其他格式创建模型实例。Pydantic 会自动验证和转换数据类型,确保数据符合模型定义。

# 导入必要的模块
from pydantic import BaseModel
from datetime import datetime

# 定义用户模型
class User(BaseModel):
    # 用户ID,整数类型
    id: int
    # 用户名,字符串类型,默认值
    name: str = "John Doe"
    # 注册时间,datetime类型或None,默认值
    signup_ts: datetime | None = None
    # 朋友列表,整数列表,默认值
    friends: list[int] = []

# 外部数据(可能是从API或数据库获取的)
external_data = {
    "id": "123",  # 字符串会自动转换为整数
    "signup_ts": "2023-01-01 12:22",
    "friends": [1, 2, "3"]  # 字符串会自动转换为整数
}

# 从外部数据创建用户实例
user = User(**external_data)
# 打印用户ID(已转换为整数)
print(user.id)  # 123 (整数)
# 打印注册时间(已转换为datetime对象)
print(repr(user.signup_ts))  # datetime.datetime(2023, 1, 1, 12, 22)
# 打印朋友列表(已转换为整数列表)
print(user.friends)  # [1, 2, 3]

# 测试代码
if __name__ == "__main__":
    print(f"用户ID类型: {type(user.id)}")
    print(f"注册时间类型: {type(user.signup_ts)}")
    print(f"朋友列表类型: {type(user.friends)}")

2.2 模型导出 #

Pydantic 模型可以方便地导出为字典或 JSON 格式,这对于 API 响应、数据序列化和存储非常有用。model_dump() 方法将模型转换为字典,model_dump_json() 方法将模型转换为 JSON 字符串。

# 导入必要的模块
from pydantic import BaseModel
from datetime import datetime

# 定义用户模型
class User(BaseModel):
    # 用户ID,整数类型
    id: int
    # 用户名,字符串类型
    name: str = "John Doe"
    # 注册时间,datetime类型或None
    signup_ts: datetime | None = None
    # 朋友列表,整数列表
    friends: list[int] = []

# 创建用户实例
user = User(id=123, name="Alice", friends=[1, 2, 3])

# 转换为字典
user_dict = user.model_dump()
print("模型转字典:")
print(user_dict)

# 转换为JSON字符串
user_json = user.model_dump_json()
print("\n模型转JSON:")
print(user_json)

# 测试代码
if __name__ == "__main__":
    print(f"字典类型: {type(user_dict)}")
    print(f"JSON类型: {type(user_json)}")

2.3 验证错误处理 #

当输入数据不符合模型定义时,Pydantic 会抛出 ValidationError 异常。这个异常包含详细的错误信息,包括错误类型、位置和具体问题,有助于调试和数据验证。

# 导入必要的模块
from pydantic import BaseModel, ValidationError
from datetime import datetime

# 定义用户模型
class User(BaseModel):
    # 用户ID,整数类型
    id: int
    # 用户名,字符串类型
    name: str = "John Doe"
    # 注册时间,datetime类型或None
    signup_ts: datetime | None = None
    # 朋友列表,整数列表
    friends: list[int] = []

# 测试验证错误处理
if __name__ == "__main__":
    try:
        # 尝试创建包含无效数据的用户实例
        User(id="not an int", friends=["not number"])
    except ValidationError as e:
        # 打印详细的错误信息
        print("验证错误详情:")
        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',
            },
            {
                'type': 'int_parsing',
                'loc': ('friends', 0),
                'msg': 'Input should be a valid integer, unable to parse string as an integer',
                'input': 'not number',
            }
        ]
        """

3. 高级特性 #

3.1 字段类型 #

Pydantic 支持丰富的字段类型,包括基本类型、特殊字符串类型、复杂类型和自定义类型。这些类型提供了强大的数据验证和转换能力。

# 导入必要的模块
from pydantic import BaseModel, EmailStr, HttpUrl, Field
from typing import Literal, Union
from datetime import datetime
from uuid import UUID

# 定义高级模型,展示各种字段类型
class AdvancedModel(BaseModel):
    # 基本类型
    name: str
    age: int

    # 特殊字符串类型 - 邮箱验证
    email: EmailStr
    # 特殊字符串类型 - URL验证
    website: HttpUrl

    # 复杂类型 - UUID
    uuid: UUID
    # 复杂类型 - 时间戳
    timestamp: datetime

    # 联合类型 - 可以是整数或字符串
    value: Union[int, str]

    # 字面量类型 - 只能是"active"或"inactive"
    status: Literal["active", "inactive"] = "active"

    # 字段配置 - 密码字段,长度8-32,只允许字母数字
    password: str = Field(..., min_length=8, max_length=32, regex="[A-Za-z0-9]+")

# 测试代码
if __name__ == "__main__":
    try:
        # 创建高级模型实例
        model = AdvancedModel(
            name="Test User",
            age=25,
            email="test@example.com",
            website="https://example.com",
            uuid="123e4567-e89b-12d3-a456-426614174000",
            timestamp="2023-01-01T12:00:00",
            value=42,
            password="secure123"
        )
        print("模型创建成功!")
        print(f"状态: {model.status}")
    except Exception as e:
        print(f"创建失败: {e}")

3.2 验证器 #

Pydantic 允许使用 @validator 装饰器定义自定义验证逻辑。验证器可以检查单个字段或多个字段之间的关系,提供灵活的数据验证能力。

# 导入必要的模块
from pydantic import BaseModel, validator

# 定义用户模型,包含自定义验证器
class UserModel(BaseModel):
    # 用户名,字符串类型
    username: str
    # 密码1,字符串类型
    password1: str
    # 密码2,字符串类型
    password2: str

    # 验证用户名必须包含字母
    @validator("username")
    def username_must_contain_letter(cls, v):
        # 检查是否包含字母
        if not any(c.isalpha() for c in v):
            raise ValueError("必须包含字母")
        return v

    # 验证两个密码是否匹配
    @validator("password2")
    def passwords_match(cls, v, values, **kwargs):
        # 检查password1是否在values中,且与password2不匹配
        if "password1" in values and v != values["password1"]:
            raise ValueError("密码不匹配")
        return v

# 测试代码
if __name__ == "__main__":
    try:
        # 测试有效数据
        user = UserModel(username="user123", password1="pass123", password2="pass123")
        print("用户创建成功!")
    except Exception as e:
        print(f"创建失败: {e}")

    try:
        # 测试无效用户名(不包含字母)
        user = UserModel(username="123", password1="pass123", password2="pass123")
    except Exception as e:
        print(f"用户名验证失败: {e}")

    try:
        # 测试密码不匹配
        user = UserModel(username="user123", password1="pass123", password2="different")
    except Exception as e:
        print(f"密码验证失败: {e}")

3.3 模型配置 #

Pydantic 模型可以通过 model_config 进行配置,控制模型的行为,如是否允许额外字段、是否使模型不可变、是否添加示例等。

# 导入必要的模块
from pydantic import BaseModel

# 定义配置模型,展示各种配置选项
class ConfigModel(BaseModel):
    # 模型配置字典
    model_config = {
        "extra": "forbid",  # 禁止额外字段
        "frozen": True,     # 使模型不可变
        "json_schema_extra": {
            "examples": [{
                "name": "Example",
                "age": 25
            }]
        }
    }

    # 模型字段
    name: str
    age: int

# 测试代码
if __name__ == "__main__":
    try:
        # 创建配置模型实例
        model = ConfigModel(name="Test", age=25)
        print("模型创建成功!")
        print(f"名称: {model.name}, 年龄: {model.age}")

        # 尝试修改字段(应该失败,因为frozen=True)
        try:
            model.name = "New Name"
        except Exception as e:
            print(f"修改字段失败(预期): {e}")

    except Exception as e:
        print(f"创建失败: {e}")

3.4 嵌套模型 #

Pydantic 支持嵌套模型,可以在一个模型中包含其他模型。这对于表示复杂的数据结构非常有用,如用户包含多个地址等。

# 导入必要的模块
from typing import List
from pydantic import BaseModel

# 定义地址模型
class Address(BaseModel):
    # 街道地址
    street: str
    # 城市
    city: str
    # 邮政编码
    zip_code: str

# 定义用户模型,包含地址列表
class User(BaseModel):
    # 用户名
    name: str
    # 地址列表
    addresses: List[Address]

# 测试代码
if __name__ == "__main__":
    # 创建用户实例,包含多个地址
    user = User(
        name="John",
        addresses=[
            {"street": "123 Main St", "city": "Anytown", "zip_code": "12345"},
            {"street": "456 Oak Ave", "city": "Somewhere", "zip_code": "67890"}
        ]
    )

    print(f"用户: {user.name}")
    print("地址列表:")
    for i, addr in enumerate(user.addresses, 1):
        print(f"  地址{i}: {addr.street}, {addr.city} {addr.zip_code}")

4. 实用功能 #

4.1 动态模型创建 #

Pydantic 支持动态创建模型,这在需要根据运行时条件创建不同数据结构的场景中非常有用。create_model 函数允许在运行时创建模型类。

# 导入必要的模块
from pydantic import BaseModel, create_model

# 动态创建模型
DynamicModel = create_model(
    "DynamicModel",
    name=(str, ...),  # 必填字段,字符串类型
    age=(int, 18),    # 可选字段,整数类型,默认值18
)

# 测试代码
if __name__ == "__main__":
    # 创建动态模型实例
    obj = DynamicModel(name="Alice")
    print(f"动态模型: {obj}")  # name='Alice' age=18

    # 创建另一个实例,指定年龄
    obj2 = DynamicModel(name="Bob", age=25)
    print(f"动态模型2: {obj2}")  # name='Bob' age=25

4.2 数据解析 #

Pydantic 提供了强大的数据解析功能,可以将各种格式的数据转换为模型实例。parse_obj_as 用于解析对象,parse_raw_as 用于解析原始数据如 JSON 字符串。

# 导入必要的模块
from pydantic import BaseModel, parse_obj_as, parse_raw_as

# 定义用户模型
class User(BaseModel):
    # 用户名
    name: str
    # 年龄,可选
    age: int = 18

# 测试代码
if __name__ == "__main__":
    # 解析对象列表
    users = parse_obj_as(list[User], [{"name": "John"}, {"name": "Alice"}])
    print("解析对象列表:")
    for user in users:
        print(f"  {user.name} (年龄: {user.age})")

    # 解析JSON字符串
    users_json = parse_raw_as(list[User], '[{"name": "John"}, {"name": "Alice"}]')
    print("\n解析JSON字符串:")
    for user in users_json:
        print(f"  {user.name} (年龄: {user.age})")

4.3 与 JSON Schema 集成 #

Pydantic 模型可以生成 JSON Schema,这对于 API 文档生成、数据验证和前端开发非常有用。model_json_schema() 方法返回模型的 JSON Schema 定义。

# 导入必要的模块
from pydantic import BaseModel

# 定义用户模型
class User(BaseModel):
    # 用户名,必填字段
    name: str
    # 年龄,可选字段
    age: int = 18

# 测试代码
if __name__ == "__main__":
    # 生成JSON Schema
    schema = User.model_json_schema()
    print("JSON Schema:")
    print(schema)
    """
    输出示例:
    {
        "title": "User",
        "type": "object",
        "properties": {
            "name": {"title": "Name", "type": "string"},
            "age": {"title": "Age", "type": "integer", "default": 18},
        },
        "required": ["name"]
    }
    """

5. 性能优化 #

5.1 使用严格模式 #

Pydantic 提供了严格模式,使用 StrictInt、StrictStr 等类型可以防止自动类型转换,确保数据类型的严格性。这在需要精确控制数据类型的场景中非常有用。

# 导入必要的模块
from pydantic import StrictInt, StrictStr, BaseModel

# 定义严格模式模型
class StrictModel(BaseModel):
    # 严格字符串类型,必须是字符串,不接受数字等
    name: StrictStr
    # 严格整数类型,必须是整数,不接受字符串数字
    age: StrictInt

# 测试代码
if __name__ == "__main__":
    try:
        # 创建严格模式模型实例
        model = StrictModel(name="Alice", age=25)
        print("严格模式模型创建成功!")
        print(f"名称: {model.name}, 年龄: {model.age}")
    except Exception as e:
        print(f"创建失败: {e}")

    try:
        # 尝试使用字符串数字作为年龄(应该失败)
        model = StrictModel(name="Bob", age="25")
    except Exception as e:
        print(f"严格模式验证失败(预期): {e}")

5.2 自定义类型 #

Pydantic 允许创建自定义类型,通过实现 __get_pydantic_core_schema__ 方法可以定义自己的验证逻辑。这对于特殊的数据格式或业务规则非常有用。

# 导入必要的模块
from pydantic import BaseModel, GetCoreSchemaHandler
from pydantic_core import core_schema
from typing import Any

# 定义自定义类型
class CustomType:
    # 实现Pydantic核心schema方法
    @classmethod
    def __get_pydantic_core_schema__(
        cls, source_type: Any, handler: GetCoreSchemaHandler
    ) -> core_schema.CoreSchema:
        # 返回字符串schema,并在验证后调用validate方法
        return core_schema.no_info_after_validator_function(
            cls.validate,
            core_schema.str_schema(),
        )

    # 自定义验证方法
    @classmethod
    def validate(cls, v: str) -> str:
        # 检查字符串是否以"custom_"开头
        if not v.startswith("custom_"):
            raise ValueError("必须以custom_开头")
        return v

# 定义使用自定义类型的模型
class MyModel(BaseModel):
    # 使用自定义类型
    value: CustomType

# 测试代码
if __name__ == "__main__":
    try:
        # 创建使用自定义类型的模型实例
        model = MyModel(value="custom_test")
        print("自定义类型验证成功!")
        print(f"值: {model.value}")
    except Exception as e:
        print(f"创建失败: {e}")

    try:
        # 尝试使用无效值(不以custom_开头)
        model = MyModel(value="invalid_test")
    except Exception as e:
        print(f"自定义类型验证失败(预期): {e}")

6. 与 FastAPI 集成 #

Pydantic 是 FastAPI 的核心组件,用于请求和响应的数据验证。FastAPI 自动使用 Pydantic 模型来验证请求数据、生成响应模型和创建 API 文档。

# 导入必要的模块
from fastapi import FastAPI
from pydantic import BaseModel

# 创建FastAPI应用实例
app = FastAPI()

# 定义项目模型
class Item(BaseModel):
    # 项目名称
    name: str
    # 项目描述,可选
    description: str | None = None
    # 项目价格
    price: float
    # 税费,可选
    tax: float | None = None

# 定义POST端点,使用Pydantic模型验证请求数据
@app.post("/items/")
async def create_item(item: Item):
    # 返回项目数据(自动转换为字典)
    return {"item": item.model_dump()}

# 测试代码(模拟FastAPI请求)
if __name__ == "__main__":
    # 模拟请求数据
    request_data = {
        "name": "Laptop",
        "description": "High-performance laptop",
        "price": 999.99,
        "tax": 99.99
    }

    # 创建项目实例(模拟FastAPI的自动验证)
    item = Item(**request_data)
    print("FastAPI集成测试:")
    print(f"项目: {item.name}")
    print(f"价格: ${item.price}")
    print(f"税费: ${item.tax}")

7. 最佳实践 #

使用 Pydantic 时有一些重要的最佳实践,遵循这些实践可以提高代码质量、性能和可维护性。

  1. 明确类型:尽可能使用具体的类型注解
  2. 合理使用可选字段:使用 Optional 或设置默认值
  3. 验证器简洁:保持验证器逻辑简单
  4. 文档注释:为模型和字段添加文档字符串
  5. 性能敏感场景:考虑使用严格模式或自定义类型
  6. 错误处理:妥善处理 ValidationError

8. 常见问题 #

8.1 循环引用 #

当模型之间存在循环引用时,需要使用 ForwardRef 来解决。这在复杂的数据结构中很常见,如用户和团队之间的相互引用。

# 导入必要的模块
from typing import ForwardRef
from pydantic import BaseModel

# 前向引用声明
UserRef = ForwardRef("User")

# 定义团队模型
class Team(BaseModel):
    # 团队名称
    name: str
    # 团队成员列表(使用前向引用)
    members: list[UserRef]

# 定义用户模型
class User(BaseModel):
    # 用户名称
    name: str
    # 所属团队(可选)
    team: Team | None = None

# 更新前向引用
Team.model_rebuild()

# 测试代码
if __name__ == "__main__":
    try:
        # 创建团队
        team = Team(name="开发团队", members=[])
        # 创建用户
        user = User(name="张三", team=team)
        print("循环引用模型创建成功!")
        print(f"用户: {user.name}")
        print(f"团队: {user.team.name if user.team else '无'}")
    except Exception as e:
        print(f"创建失败: {e}")

8.2 自定义 JSON 编码 #

Pydantic 允许自定义 JSON 编码,这对于特殊的数据类型如 datetime 非常有用。可以通过配置 json_encoders 来自定义序列化行为。

# 导入必要的模块
from datetime import datetime
from pydantic import BaseModel

# 定义自定义JSON编码器模型
class CustomEncoder(BaseModel):
    # 日期时间字段
    dt: datetime

    # 模型配置
    class Config:
        # 自定义JSON编码器
        json_encoders = {
            # 将datetime对象编码为字符串格式
            datetime: lambda v: v.strftime("%Y-%m-%d")
        }

# 测试代码
if __name__ == "__main__":
    # 创建自定义编码器模型实例
    model = CustomEncoder(dt=datetime(2023, 1, 1, 12, 0, 0))

    # 转换为JSON
    json_str = model.model_dump_json()
    print("自定义JSON编码:")
    print(json_str)
    # 输出: {"dt": "2023-01-01"}

9. 版本变化 #

Pydantic v2 相比 v1 有重要变化,包括性能提升、API 改进和架构优化。了解这些变化有助于正确使用新版本的功能。

Pydantic v2 的重要变化:

  1. 核心逻辑用 Rust 重写,性能大幅提升
  2. 新的 model_dump() 和 model_dump_json() 方法替代旧的 dict() 和 json()
  3. 配置方式从类属性改为 model_config 字典
  4. 更灵活的验证和序列化架构

总结 #

Pydantic 通过 Python 类型注解提供了强大的数据验证和转换功能,是现代 Python 开发中不可或缺的工具。它的主要优势在于:

  1. 简洁性:使用 Python 原生类型提示
  2. 强大验证:内置丰富的验证逻辑
  3. 高性能:核心部分用 Rust 实现
  4. 广泛集成:与 FastAPI、Django 等框架良好集成

掌握 Pydantic 可以显著提高数据处理代码的健壮性和可维护性,特别是在 API 开发和配置管理场景中。

访问验证

请输入访问令牌

Token不正确,请重新输入