Skip to content

04 · 类、类型注解与 Pydantic ​

🎯 难度:初级⏱ 预计:60 分钟# class# typing# Pydantic

为什么要学类? ​

SDK 经常这样写:client = OpenAI(...),随后 client.chat.completions.create(...)。你不需要先设计复杂面向对象系统,但要理解「类创建实例,实例携带状态和方法」。

python
class Counter:
    def __init__(self, initial: int = 0):  # 类似 constructor
        self.value = initial             # 类似 this.value

    def increment(self):
        self.value += 1

counter = Counter(3)
counter.increment()
print(counter.value)  # 4

self 相当于实例自身,普通实例方法的第一个参数必须写它;调用时 Python 会自动传入。

Agent 常见类型注解 ​

python
from typing import Literal, TypedDict

class Message(TypedDict):
    role: Literal["system", "user", "assistant"]
    content: str

messages: list[Message] = [{"role": "user", "content": "你好"}]
result: str | None = None  # 类似 TS 的 string | null
  • list[str]:字符串列表。
  • dict[str, int]:键是字符串,值是整数。
  • str | None:可能为空。
  • Literal[...]:枚举式字面量类型。
  • TypedDict:为普通 dict 提供形状声明,不会验证运行时数据。

Pydantic:可以运行的 Schema ​

你熟悉 Zod 的话,可以把 Pydantic 理解为 Python 的「Schema 校验 + 数据对象 + JSON Schema 生成」工具。

bash
uv add "pydantic>=2,<3"
python
from pydantic import BaseModel, Field, ValidationError

class WeatherArgs(BaseModel):
    city: str = Field(min_length=1, description="城市名称")
    days: int = Field(default=1, ge=1, le=7, description="预报天数")

args = WeatherArgs.model_validate({"city": "北京", "days": 3})
print(args.city)                  # 北京
print(args.model_dump())          # 转成 dict
print(args.model_dump_json())     # 转成 JSON 文本
print(WeatherArgs.model_json_schema())  # 给大模型看的 JSON Schema

try:
    WeatherArgs(city="北京", days=30)
except ValidationError as error:
    print(error.errors()[0]["type"])  # less_than_equal

这里的 ge 表示大于等于,le 表示小于等于。请注意:Field 的 description 是给人和模型看的,约束才是程序执行的。

默认会进行部分类型转换

例如字符串 "3" 可能被转换为整数 3。安全敏感参数可以使用 model_validate(data, strict=True),拒绝宽松转换。无论使用哪种模式,都要在工具执行前校验。

装饰器:先把它读懂 ​

你会看到这样的语法:

python
from functools import wraps

def trace(fn):
    @wraps(fn)
    def wrapped(*args, **kwargs):
        print(f"调用 {fn.__name__}")
        return fn(*args, **kwargs)
    return wrapped

@trace
def add(a, b):
    return a + b

print(add(1, 2))

@trace 大致等价于定义函数后执行 add = trace(add)。在 FastAPI 中 @app.post(...) 注册路由,在 MCP 中 @mcp.tool() 注册工具。装饰器不一定返回包装函数,也可能仅做注册;先记住「把函数交给另一个函数处理」即可。

动手练习 ​

定义 Task 模型:title 非空字符串,priority 只能是 low / medium / high,done 默认 False。验证一条有效数据和一条非法优先级数据。

参考答案
python
from typing import Literal
from pydantic import BaseModel, Field, ValidationError

class Task(BaseModel):
    title: str = Field(min_length=1)
    priority: Literal["low", "medium", "high"] = "medium"
    done: bool = False

print(Task(title="学习 Python").model_dump())
try:
    Task(title="测试", priority="urgent")
except ValidationError:
    print("非法优先级已被拒绝")

检查点:类型注解与 Pydantic 校验之间的区别是什么?模型调用工具时,应该信任参数的类型声明,还是在运行时再验证一次?

用心写给每一个想入门 Agent 开发的前端工程师