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

为何能重载typing.Dict的__getattr__,却无法重载typing_extensions.TypedDict?

问题原因与解决方案

为什么typing_extensions.TypedDict子类的__getattr__会被忽略?

TypedDict本质上是仅用于类型注解的虚拟类,Python解释器在运行时会将其子类实例化为普通dict对象,本不应保留自定义方法。但typing.TypedDict和typing_extensions.TypedDict的运行时实现逻辑存在差异:

  • Python 3.10的标准库typing.TypedDict元类处理逻辑,意外保留了子类中的自定义方法;
  • typing_extensions.TypedDict的实现更严格遵循TypedDict的设计初衷,完全剥离子类自定义方法,直接返回原生dict实例,导致重载的__getattr__无法执行。

解决办法

方案1:类型注解与运行时类分离

单独定义用于类型检查的TypedDict,再用继承dict的类实现运行时属性访问逻辑:

from typing_extensions import TypedDict, NotRequired

# 仅用于类型注解的TypedDict
class MyData(TypedDict):
    a: int
    b: NotRequired[str]

# 实现属性访问的自定义dict子类
class AttrDict(dict):
    def __getattr__(self, key):
        return self[key]

# 结合使用
f: MyData = AttrDict(a=1)
print(f['a'])  # 输出1
print(f.a)     # 输出1

这种方式既符合PEP 655要求使用typing_extensions的NotRequired,又能实现预期的运行时行为。

方案2:自定义元类修正实例化逻辑

通过元类覆盖typing_extensions.TypedDict的默认实例化行为,强制保留自定义方法:

from typing_extensions import TypedDict

class AttrTypedDictMeta(type):
    def __call__(cls, **kwargs):
        instance = super().__call__(**kwargs)
        instance.__class__ = cls
        return instance

class WorkingDict(TypedDict, metaclass=AttrTypedDictMeta):
    a: int
    def __getattr__(self, key):
        return self[key]

f = WorkingDict(a=1)
print(f['a'])  # 输出1
print(f.a)     # 输出1

注意:此方法属于hack手段,可能随Python或typing_extensions版本更新失效,仅推荐临时场景使用。

方案3:升级Python版本(长期方案)

Python 3.11及以上版本的标准库typing已内置NotRequired,可直接从typing导入TypedDict和NotRequired,沿用typing.TypedDict子类保留方法的行为。

关于PEP标准的说明

PEP 655允许在Python版本不支持内置NotRequired时,分开从typing导入TypedDict、从typing_extensions导入NotRequired——这是官方推荐的过渡方案,完全符合合规性要求,也不会存在词法分析器兼容性问题。


内容的提问来源于stack exchange,提问作者en_Knight

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 08:42:43