如何定义同一TypedDict的两个版本:全量版与非全量版?
问题
我要为API客户端定义两个TypedDict版本:
- 非全量版(
PartialDict):用于局部更新路由输入,允许只包含字段子集 - 全量版(
FullDict):用于响应,必须包含所有字段
尝试了以下代码但未达到预期效果:
class PartialDict(TypedDict, total=False): name: str age: int class FullDict(PartialDict, total=True): pass
Mypy 1.13对下方代码均未报错(y: FullDict = {}本应报错):
x: PartialDict = {} # 预期正常 y: FullDict = {} # 预期报错但实际无提示
反转继承关系后:
class FullDict(TypedDict, total=True): name: str age: int class PartialDict(FullDict, total=False): pass
Mypy会对两行代码都报错:
mymodule/types.py:38: error: Missing keys ("name", "age") for TypedDict "PartialDict" [typeddict-item] mymodule/types.py:39: error: Missing keys ("name", "age") for TypedDict "FullDict" [typeddict-item]
我需要避免重复定义类(实际场景包含数十个键),该如何正确定义类型?
解决方案
核心原因
TypedDict的total参数仅作用于当前类中定义的字段,继承来的字段会保留原有的必需性:
- 继承
total=False的父类时,子类设total=True不会把继承字段改为必需 - 继承
total=True的父类时,子类设total=False仅影响子类新增字段,继承字段仍为必需
方法1:手动指定__required_keys__和__optional_keys__
通过显式设置TypedDict的类属性,统一维护字段定义,避免重复:
from typing import TypedDict # 定义所有字段的基础类 class _BaseDict(TypedDict): name: str age: int # 在这里添加所有其他字段 # 全量版:所有字段必需 class FullDict(_BaseDict): __required_keys__ = _BaseDict.__annotations__.keys() __optional_keys__ = set() # 非全量版:所有字段可选 class PartialDict(_BaseDict): __required_keys__ = set() __optional_keys__ = _BaseDict.__annotations__.keys()
测试验证:
x: PartialDict = {} # 正常通过 y: FullDict = {} # Mypy报错:Missing keys ("name", "age") for TypedDict "FullDict"
方法2:使用Required/NotRequired(Python 3.11+ 或 typing-extensions)
如果使用Python 3.11及以上,或通过typing-extensions库兼容低版本,可以用泛型标记字段必需性,动态生成两个版本:
from typing import TypedDict, Required, NotRequired # 统一维护字段映射 _FIELDS = { "name": str, "age": int, # 更多字段... } # 生成全量TypedDict:所有字段为Required FullDict = TypedDict("FullDict", {k: Required[v] for k, v in _FIELDS.items()}, total=True) # 生成非全量TypedDict:所有字段为NotRequired PartialDict = TypedDict("PartialDict", {k: NotRequired[v] for k, v in _FIELDS.items()}, total=False)
这种方式无需定义类,仅维护一份字段列表即可生成两个TypedDict类型。
内容的提问来源于stack exchange,提问作者bfontaine
相关产品推荐
相关产品推荐

