总结 TypedDict、Pydantic、Field、Annotated、Optional 等 Python 类型与校验工具的核心写法与组合方式
·
下面总结 TypedDict、Pydantic、Field、Annotated、Optional 这些 Python 类型与校验工具的核心写法与组合方式。
1. Optional —— 可选类型
作用:类型提示中表示“可以是某种类型,也可以是 None”。等价于 Union[T, None]。
写法:
from typing import Optional
name: Optional[str] = None # 变量可以是 str 或 None
在 Pydantic 中:Optional[str] 本身不设置默认值,需要配合 = None 才变为可选字段。
from pydantic import BaseModel
from typing import Optional
class User(BaseModel):
nickname: Optional[str] = None # 可选,默认 None
age: Optional[int] # 必填!必须显式传值或 None
2. TypedDict —— 结构化字典(静态检查)
作用:定义字典的键名及对应值的类型,用于静态类型检查(mypy、Pyright),无运行时行为。
基本写法:
from typing import TypedDict
class UserDict(TypedDict):
name: str
age: int
可选字段(Python 3.11+ 或 typing_extensions):
from typing import TypedDict
from typing_extensions import NotRequired
class UserDict(TypedDict):
name: str
age: NotRequired[int] # 键 age 可以缺失
使用 total=False(全部字段可选):
class UserDict(TypedDict, total=False):
name: str
age: int
注意:TypedDict 不支持 Field、默认值、运行时验证。
3. Pydantic —— 运行时数据验证与解析
作用:通过 BaseModel 定义模型,自动完成类型转换、校验、序列化、文档生成。
基本写法:
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
可选字段(默认值 None):
class User(BaseModel):
name: str
age: int = None # 等价于 Optional[int] = None
# 或
nickname: Optional[str] = None
运行时校验:实例化时自动检查类型,无效数据抛出 ValidationError。
4. Field —— Pydantic 字段元数据
作用:为 Pydantic 模型字段提供额外信息,如默认值、描述、验证约束、别名等。
基本写法:
from pydantic import BaseModel, Field
class Product(BaseModel):
name: str = Field(..., min_length=1, description="产品名称")
price: float = Field(gt=0, le=10000, description="价格")
stock: int = Field(default=0, ge=0)
常用参数:
default:默认值default_factory:生成默认值的可调用对象gt,ge,lt,le:数值范围min_length,max_length:字符串长度regex:正则表达式description:描述(用于生成 JSON Schema)alias:字段别名
5. Annotated —— 类型元数据容器
作用:Python 3.9+ 引入,将额外信息(如验证、描述)附着到类型上,供工具或库解析。
基本写法:
from typing import Annotated
# 附加一个字符串元数据
UserName = Annotated[str, "用户的姓名"]
与 Pydantic 结合(最常用):
from pydantic import BaseModel, Field, PositiveInt
from typing import Annotated
class User(BaseModel):
age: Annotated[int, Field(gt=0, lt=150, description="年龄")]
score: Annotated[float, Field(ge=0, le=100)]
uid: Annotated[int, PositiveInt()] # 使用 annotated-types 库的约束
与 TypedDict 结合(Pydantic 支持):
from typing import TypedDict, Annotated
from pydantic import Field, TypeAdapter
class UserDict(TypedDict):
name: Annotated[str, Field(min_length=1)]
age: Annotated[int, Field(gt=0)]
# 运行时验证
adapter = TypeAdapter(UserDict)
data = adapter.validate_python({"name": "张三", "age": 25})
6. 组合对比:TypedDict vs Pydantic BaseModel
| 特性 | TypedDict | Pydantic BaseModel |
|---|---|---|
| 目的 | 静态类型检查 | 运行时验证 + 序列化 |
| 默认值 | ❌ | ✅ Field(default=...) |
| 可选字段 | NotRequired 或 total=False | Optional[T] = None |
| 字段描述 | ❌ | ✅ Field(description=...) |
| 数值约束 | ❌ | ✅ Field(gt=0) |
| 运行时类型转换 | ❌ | ✅(如 "123" → 123) |
| JSON Schema 生成 | ❌(需第三方) | ✅ .model_json_schema() |
| 内存/性能 | 极低(纯字典) | 较高(模型实例) |
7. 最佳实践组合建议
- 仅需静态类型检查,无运行时逻辑:
TypedDict+NotRequired+Optional - 需要运行时校验 + 默认值 + API 文档:
Pydantic BaseModel+Field+Optional - 需要强约束但想用字典结构(例如已存在字典数据):
TypedDict+Annotated+ Pydantic 的TypeAdapter - 复杂校验逻辑(跨字段验证):Pydantic 模型的
@model_validator或@field_validator
示例:一个企业级数据模型(Pydantic)
from pydantic import BaseModel, Field, field_validator
from typing import Optional, Annotated
class Student(BaseModel):
name: Annotated[str, Field(min_length=2, max_length=20)]
age: Annotated[int, Field(ge=6, le=30)]
gender: Optional[str] = Field(None, pattern="^(男|女|其他)$")
grades: list[int] = Field(default_factory=list, max_items=50)
@field_validator("grades")
def check_grades(cls, v):
if any(g < 0 or g > 100 for g in v):
raise ValueError("成绩必须在 0~100 之间")
return v
8. 关键易错点
Optional[T]不等于T | None语义相同,但Optional[T] = None才使字段可选,若只写Optional[T]仍是必填。TypedDict的字段名在运行时是普通字典键,不会被转换为属性。Annotated中的元数据顺序可任意,但通常第一个是类型,后面跟多个元数据项。- Pydantic 的
Field(default=...)与Annotated结合时,避免在Annotated内外重复定义默认值,会导致歧义。
更多推荐



所有评论(0)