You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何定义同一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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 10:23:28