跳转到内容

Python/pydantic

维基教科书,自由的教学读本

pydantic是一个具有高级功能的Python的数据容器和数据验证的第三方包。

安装

[编辑]
pip install pydantic

基础用法

[编辑]
from pydantic import BaseModel

class Student(BaseModel):
    name: str
    age: int
    grade: float
    is_active: bool = True    
    layers: List[int] = [128, 64] # ✅ 初始化安全:每个实例都是新列表

# ✅ 正常创建
student = Student(name="张三", age=20, grade=85.5)
print(student)
# name='张三' age=20 grade=85.5 is_active=True

# ✅ 自动类型转换
student2 = Student(name="李四", age="22", grade="90.0")
print(student2.age)  # 22 (int) - 从字符串自动转换
print(type(student2.age))  # <class 'int'>

数据验证

[编辑]
from pydantic import BaseModel, ValidationError

class Student(BaseModel):
    name: str
    age: int
    grade: float

# ❌ 验证失败
try:
    student = Student(name=123, age="不是数字", grade=85.5)
except ValidationError as e:
    print(e)

输出:

2 validation errors for Student
name
  Input should be a valid string [type=string_type, input_value=123, input_type=int]
age
  Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='不是数字', input_type=str]

高级验证

[编辑]
from pydantic import BaseModel, Field, field_validator, EmailStr
from typing import Annotated

class User(BaseModel):
    # 字段级验证
    username: str = Field(min_length=3, max_length=20, pattern=r'^[a-zA-Z0-9_]+$')
    age: Annotated[int, Field(gt=0, lt=150)]  # 0 < age < 150
    email: EmailStr  # 自动验证邮箱格式
    score: float = Field(ge=0.0, le=100.0)  # 0 <= score <= 100
    
    # 自定义验证器
    @field_validator('username')
    @classmethod
    def username_must_be_lowercase(cls, v: str) -> str:
        if not v.islower():
            raise ValueError('用户名必须是小写字母')
        return v

# ✅ 验证通过
user = User(username="zhangsan", age=25, email="zhangsan@example.com", score=85.5)

# ❌ 验证失败
try:
    user = User(username="ab", age=200, email="invalid", score=150)
except ValidationError as e:
    print(e)
    # username: 至少3个字符
    # age: 必须小于150
    # email: 邮箱格式错误
    # score: 必须小于等于100

JSON 序列化

[编辑]
from pydantic import BaseModel
from pathlib import Path
from datetime import datetime

class Experiment(BaseModel):
    name: str
    data_path: Path
    created_at: datetime
    parameters: dict

exp = Experiment(
    name="实验001",
    data_path="/data/exp001",
    created_at="2024-01-15T10:30:00",
    parameters={"learning_rate": 0.001, "epochs": 100}
)

# 转为字典
print(exp.model_dump())
# {
#     'name': '实验001',
#     'data_path': PosixPath('/data/exp001'),
#     'created_at': datetime.datetime(2024, 1, 15, 10, 30),
#     'parameters': {'learning_rate': 0.001, 'epochs': 100}
# }

# 转为 JSON 字符串
print(exp.model_dump_json(indent=2))
# {
#   "name": "实验001",
#   "data_path": "/data/exp001",
#   "created_at": "2024-01-15T10:30:00",
#   "parameters": {
#     "learning_rate": 0.001,
#     "epochs": 100
#   }
# }

# 从 JSON 加载
json_str = '{"name": "实验002", "data_path": "/data/exp002", "created_at": "2024-01-16T11:00:00", "parameters": {}}'
exp2 = Experiment.model_validate_json(json_str)
print(exp2.name)  # 实验002

嵌套模型

[编辑]
from pydantic import BaseModel
from typing import List

class Address(BaseModel):
    street: str
    city: str
    country: str

class Company(BaseModel):
    name: str
    address: Address

class Employee(BaseModel):
    name: str
    age: int
    company: Company
    skills: List[str]

# 创建嵌套对象
employee = Employee(
    name="张三",
    age=30,
    company={
        "name": "科技公司",
        "address": {
            "street": "中关村大街1号",
            "city": "北京",
            "country": "中国"
        }
    },
    skills=["Python", "机器学习", "数据分析"]
)

print(employee.company.address.city)  # 北京
print(employee.model_dump_json(indent=2))

配置选项

[编辑]
from pydantic import BaseModel, ConfigDict

class StrictModel(BaseModel):
    model_config = ConfigDict(
        str_strip_whitespace=True,  # 自动去除字符串首尾空格
        validate_assignment=True,   # 赋值时也验证
        frozen=True,                # 不可变对象
        extra='forbid'              # 禁止额外字段
    )
    
    name: str
    age: int

# ✅ 自动去除空格
model = StrictModel(name="  张三  ", age=25)
print(model.name)  # "张三"

# ❌ 不可变
# model.age = 30  # ValidationError

# ❌ 禁止额外字段
try:
    model = StrictModel(name="李四", age=30, extra_field="不允许")
except ValidationError as e:
    print(e)  # Extra inputs are not permitted