TypedDict 仅在类型检查阶段生效,运行时不校验字典结构;Python 3.11+ 支持 Required/NotRequired 标注可选字段,但依然不影响运行时;需运行时校验应使用 pydantic、dataclasses 或手动验证。

TypedDict 不是运行时校验工具,它只在类型检查阶段起作用
直接用 TypedDict 定义类,Python 解释器在运行时完全不检查字典结构——哪怕你传个空字典、缺字段、多字段、类型全错,代码照样执行成功。它只对 mypy、pylance、pyright 这类类型检查器生效。
常见错误现象:my_dict: MyDict = {"name": 123} 在 VS Code 里标红(类型检查报错),但 python script.py 仍能跑通,毫无异常。
- 如果你需要运行时校验,得额外用
pydantic、dataclasses或手写验证逻辑 -
TypedDict的核心价值是让 IDE 补全字段、提前暴露拼写错误和类型不匹配 - Python 3.11 开始支持
Required和NotRequired,但它们也仅影响类型检查,不改变运行时行为
定义 TypedDict 时怎么标注可选字段(Python 3.11+)
3.11 引入了 typing.Required 和 typing.NotRequired,替代旧版的字符串注释写法(如 "age?: int" 已弃用)。
示例:
from typing import TypedDict, Required, NotRequired <p>class User(TypedDict): name: str age: Required[int] # 必填字段(默认行为,可省略 Required[]) email: NotRequired[str] # 可选字段:可以不存在,存在则必须是 str </p>
注意点:
-
NotRequired字段在字典中可以完全缺失,也可以为None(除非你额外限制非空) - 如果字段类型本身是
Optional[str],表示“可为None”,和NotRequired[str](可完全不存在)语义不同 - 混合使用时,
NotRequired字段必须放在所有Required字段之后(否则 mypy 报错)
运行时想真正校验字典?得自己加一层判断
没有银弹。最轻量的做法是写个校验函数,配合 TypedDict 的 __annotations__ 和 __required_keys__ / __optional_keys__ 属性(Python 3.11+ 支持)。
示例:
def validate_user(d: dict) -> User:
required = User.__required_keys__
optional = User.__optional_keys__
keys = set(d.keys())
<pre class="brush:php;toolbar:false;">if not keys >= required:
missing = required - keys
raise ValueError(f"Missing required keys: {missing}")
if not keys <p></p>
说明:
-
User.__required_keys__和User.__optional_keys__是 Python 3.11 新增的只读属性,返回frozenset - 这个函数不处理嵌套
TypedDict或泛型,复杂场景建议换pydantic.BaseModel - 别依赖
isinstance(d, User)—— 它永远返回False,因为TypedDict不是运行时类型
和 pydantic BaseModel 混用要注意什么
很多人想“既用 TypedDict 做类型提示,又用 pydantic 做运行时校验”,但二者字段定义方式不兼容。
典型坑:
-
TypedDict中的NotRequired[str]≠pydantic.Field(default=None):前者允许字段缺失,后者要求字段存在且可为None - pydantic v2 的
model_validate不接受纯TypedDict类型作为目标,需显式用model_validate(dict_data) - 如果只想要类型提示 + 校验,直接用
pydantic.BaseModel更省事;TypedDict真正适合的是“零运行时开销 + IDE 友好”的纯数据契约场景
字段定义差异大,硬凑容易两边都失效。选一个主力,别指望自动互通。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











