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

子类化dict时get与__getitem__的差异及递归错误原因

为什么子类化dict时重写__getitem__会触发递归,而get()不会?

这个问题踩中了Python字典特殊方法和普通方法的关键差异,我来一步步给你理清楚:

先搞懂get()和__getitem__的基础区别

  • getitem:这是Python用来实现[]索引访问的特殊方法。当你写d['a']的时候,Python底层直接调用的就是d.__getitem__('a')。dict父类的__getitem__逻辑是:找到key就返回值,找不到就检查子类有没有实现__missing__方法,有就调用它,没有就抛KeyError。
  • get():这是dict类提供的普通实例方法,它的默认实现其实是内部调用__getitem__,但会捕获KeyError——如果key不存在,就返回你指定的默认值(默认是None)。

分析你的两个子类案例

1. MyDict(重写get()没问题)

你写的get()方法里返回self[key],这里的self[key]会触发父类dict的__getitem__(因为你没重写__getitem__)。父类的__getitem__遇到不存在的key时,会自动调用你实现的__missing__返回0,整个流程是:
d.get('c') → 调用自定义get() → self['c'] → 父类__getitem__ → 触发__missing__ → 返回0,完全没有递归。

2. MyDict2(重写__getitem__触发递归错误)

问题出在你重写的__getitem__里:return self[key]。当你调用d['a']或者d['c']时,Python会调用你这个自定义的__getitem__方法,而方法里的self[key]又会再次调用这个自定义的__getitem__,于是就陷入了无限循环:
d['a'] → 自定义__getitem__ → self['a'] → 自定义__getitem__ → ... 直到Python达到递归深度上限,抛出RecursionError。

这里的核心是:重写__getitem__时,不能直接用self[key],因为那就是在调用你自己写的这个方法。如果要复用父类的逻辑,必须显式调用父类的__getitem__,比如用super().__getitem__(key)。

修复后的MyDict2应该是这样:

class MyDict2(dict):
    def __missing__(self, key):
        return 0
    def __getitem__(self, key):
        # 调用父类的__getitem__,它会自动触发__missing__
        return super().__getitem__(key)

这样当你访问d['c']时,父类的__getitem__找不到key,就会调用你实现的__missing__返回0,完美解决递归问题。

总结两者的关键差异

  • 重写get()时,调用self[key]会触发父类的__getitem__,和当前的get()方法是两个独立的函数,不会递归。
  • 重写__getitem__时,self[key]就是在调用当前的__getitem__方法,直接这么写必然导致无限递归,必须通过super()调用父类的实现来避免。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:57:45