目 录CONTENT

文章目录

Python 开发者的 Pydantic 完整指南

Administrator
2025-11-06 / 0 评论 / 0 点赞 / 2 阅读 / 0 字

📢 转载信息

原文链接:https://machinelearningmastery.com/the-complete-guide-to-pydantic-for-python-developers/

原文作者:Bala Priya C


在本文中,您将学习如何使用 Pydantic 在 Python 中利用类型提示来验证、解析和序列化结构化数据。

我们将涵盖的主题包括:

  • 使用类型强制转换和清晰的验证错误来定义核心模型
  • 有效使用可选字段、默认值和 Field 约束
  • 编写自定义验证器、处理嵌套结构以及导出 JSON

让我们不要再浪费时间了。

The Complete Guide to Pydantic for Python Developers

Python 开发者的 Pydantic 完整指南
图片来源:Editor

引言

Python 在处理数据类型方面的灵活性在编码时很方便,但在代码接收到意外的数据格式时,可能会导致运行时错误。当您处理 API、处理配置文件或处理用户输入时,此类错误尤为常见。因此,数据验证对于构建可靠的应用程序变得至关重要。

Pydantic 通过利用 Python 的类型提示系统(您可能已经在使用了),提供了自动数据验证和序列化功能来应对这一挑战,使您能够精确定义数据应有的外观并自动强制执行这些规则。

本文将介绍使用 Pydantic 通过类型提示进行数据验证的基础知识。以下是您将学到的内容:

  • 使用类型提示创建和验证数据结构
  • 处理可选字段和默认值
  • 为特定要求构建自定义验证逻辑
  • 处理嵌套模型和复杂数据结构

让我们从基础知识开始。在继续之前,请先安装 Pydantic 库:

pip install pydantic

并跟随示例进行操作。

🔗 GitHub 上的代码链接

基础 Pydantic 模型

与需要编写大量 if 语句和类型检查的手动数据验证方法不同,Pydantic 与您现有的 Python 代码集成良好。它使用 Python 的类型提示(您可能已经在使用它们)并将其转化为强大的验证逻辑。

当数据不符合您的规范时,您会收到清晰、可操作的错误消息,而不是晦涩的运行时异常。这减少了调试时间,并使您的代码更易于维护和自我记录。

Pydantic 模型继承自 BaseModel,并使用 Python 类型提示来定义预期的数据结构:

from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int
    email: str

# Create a user
user = User(name="Alice", age="25", email="alice@example.com")

print(user.age)
print(type(user.age))

输出:

25

此代码定义了一个具有三个必需字段的 User 模型。创建 user 实例时,Pydantic 会自动将字符串 “25” 转换为整数 25。如果转换不可能(例如,为年龄传入 “abc”),它会引发带有清晰错误消息的验证错误,说明哪里出了问题。这种自动类型强制转换在处理所有内容都以字符串形式到达的 JSON 数据或表单输入时尤其有用。

可选字段和默认值

现实世界的数据通常包含缺失或可选的字段。Pydantic 使用 Optional 类型和默认值来处理这种情况:

from pydantic import BaseModel, Field
from typing import Optional

class Product(BaseModel):
    name: str
    price: float
    description: Optional[str] = None
    in_stock: bool = True
    category: str = Field(default="general", min_length=1)

# All these work
product1 = Product(name="Widget", price=9.99)
product2 = Product(name="Gadget", price=15.50, description="Useful tool")

Optional[str] 类型意味着 description 可以是字符串或 None。带有默认值的字段在创建实例时不需要提供。Field() 函数添加了验证约束。

在这里,它确保 category 至少包含一个字符。这种灵活性允许您的模型优雅地处理不完整的数据,同时仍然强制执行重要的业务规则。

Pydantic 中的自定义验证器

有时您需要的验证逻辑超出了基本的类型检查。验证器允许您实现自定义规则:

from pydantic import BaseModel, field_validator
import re

class Account(BaseModel):
    username: str
    email: str
    password: str

    @field_validator('username')
    def validate_username(cls, v):
        if len(v) < 3:
            raise ValueError('Username must be at least 3 characters')
        if not v.isalnum():
            raise ValueError('Username must be alphanumeric')
        return v.lower() # Normalize to lowercase

    @field_validator('email')
    def validate_email(cls, v):
        pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$'
        if not re.match(pattern, v):
            raise ValueError('Invalid email format')
        return v

    @field_validator('password')
    def validate_password(cls, v):
        if len(v) < 8:
            raise ValueError('Password must be at least 8 characters')
        return v

account = Account(
    username="JohnDoe123",
    email="john@example.com",
    password="secretpass123"
)

验证器在模型创建期间自动运行。它们可以转换数据(例如将用户名转换为小写)或使用描述性错误消息拒绝无效值。

cls 参数允许访问类,v 是正在验证的值。验证器按定义的顺序运行,并且可以访问先前已验证字段的值。

嵌套模型和复杂结构

实际应用程序处理分层数据。Pydantic 使嵌套验证变得简单明了:

from pydantic import BaseModel, field_validator
from typing import List, Optional
from datetime import datetime

class Address(BaseModel):
    street: str
    city: str
    state: str
    zip_code: str

    @field_validator('zip_code')
    def validate_zip(cls, v):
        if not v.isdigit() or len(v) != 5:
            raise ValueError('ZIP code must be 5 digits')
        return v

class Contact(BaseModel):
    name: str
    phone: str
    email: Optional[str] = None

class Company(BaseModel):
    name: str
    founded: datetime
    address: Address
    contacts: List[Contact]
    employee_count: int
    is_public: bool = False

# Complex nested data gets fully validated
company_data = {
    "name": "Tech Corp",
    "founded": "2020-01-15T10:00:00",
    "address": {
        "street": "123 Main St",
        "city": "San Francisco",
        "state": "CA",
        "zip_code": "94105"
    },
    "contacts": [
        {"name": "John Smith", "phone": "555-0123"},
        {"name": "Jane Doe", "phone": "555-0456", "email": "jane@techcorp.com"}
    ],
    "employee_count": 150
}

company = Company(**company_data)

Pydantic 会递归地验证整个结构。地址会根据 Address 模型规则进行验证,contacts 列表中的每个联系人都作为 Contact 模型进行验证,并且 datetime 字符串会自动解析。如果嵌套结构中有任何部分无效,您将收到一条详细错误消息,确切指出问题所在的位置。

如果一切顺利,company 对象将如下所示:

Company(name='Tech Corp', founded=datetime.datetime(2020, 1, 15, 10, 0), address=Address(street='123 Main St', city='San Francisco', state='CA', zip_code='94105'), contacts=[Contact(name='John Smith', phone='555-0123', email=None), Contact(name='Jane Doe', phone='555-0456', email='jane@techcorp.com')], employee_count=150, is_public=False)

处理 API 和 JSON

Pydantic 在处理通常格式不确定的 API 响应和 JSON 数据方面表现出色。

此示例展示了如何处理典型的 API 挑战:混合数据类型(年龄作为字符串)、各种 datetime 格式和可选字段:

from pydantic import BaseModel, Field, field_validator
from typing import Union, Optional
from datetime import datetime
import json

class APIResponse(BaseModel):
    status: str
    message: Optional[str] = None
    data: Optional[dict] = None
    timestamp: datetime = Field(default_factory=datetime.now)

class UserProfile(BaseModel):
    id: int
    username: str
    full_name: Optional[str] = None
    age: Optional[int] = Field(None, ge=0, le=150) # Age constraints
    created_at: Union[datetime, str] # Handle multiple formats
    is_verified: bool = False

    @field_validator('created_at', mode='before')
    def parse_created_at(cls, v):
        if isinstance(v, str):
            try:
                return datetime.fromisoformat(v.replace('Z', '+00:00'))
            except ValueError:
                raise ValueError('Invalid datetime format')
        return v

# Simulate API response
api_json = '''
{
    "status": "success",
    "data": {
        "id": 123,
        "username": "alice_dev",
        "full_name": "Alice Johnson",
        "age": "28",
        "created_at": "2023-01-15T10:30:00Z",
        "is_verified": true
    }
}
'''

response_data = json.loads(api_json)
api_response = APIResponse(**response_data)

if api_response.data:
    user = UserProfile(**api_response.data)
    print(f"User {user.username} created at {user.created_at}")




🚀 想要体验更好更全面的AI调用?

欢迎使用青云聚合API,约为官网价格的十分之一,支持300+全球最新模型,以及全球各种生图生视频模型,无需翻墙高速稳定,文档丰富,小白也可以简单操作。

0

评论区