下面总结 TypedDictPydanticFieldAnnotatedOptional 这些 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

特性TypedDictPydantic BaseModel
目的静态类型检查运行时验证 + 序列化
默认值Field(default=...)
可选字段NotRequiredtotal=FalseOptional[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 内外重复定义默认值,会导致歧义。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐