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

为何使用in检查时__getitem__接收的key变为0?

问题:实现__getitem__后执行key in obj时传入的key变为0

问题重现

实现了如下类:

class Mapper:
  def __getitem__(self, key):
    print(f'Retrieving {key!r}')
    if key == 'a':
      return 1
    else:
      raise KeyError('This only contains a')

单独用obj[key]可以正常工作:

>>> mapper['a']
Retrieving 'a'
1

但执行'a' in mapper时,却出现异常,且传入__getitem__的key变成了0:

>>> 'a' in mapper
Retrieving 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in __getitem__
KeyError: 'This only contains a'

原因分析

你误解了Python中in操作的默认逻辑:

  • 当类没有实现__contains__方法(你找的__hasitem__是错误的方法名,正确的是__contains__)时,Python会将对象视为序列类型,而非映射类型。
  • 此时in操作会尝试通过__getitem__从索引0开始逐个取值,直到抛出IndexError才会判定元素不存在——而不是直接用目标key去调用__getitem__并捕获KeyError。这就是为什么会传入整数0的原因。

解决方案

方案1:实现__contains__方法(推荐)

直接定义__contains__方法来判断key是否存在,这是映射类型的标准实现方式:

class Mapper:
    def __getitem__(self, key):
        print(f'Retrieving {key!r}')
        if key == 'a':
            return 1
        else:
            raise KeyError('This only contains a')
    
    def __contains__(self, key):
        # 直接判断key是否在允许的范围内
        return key == 'a'

测试验证:

>>> mapper = Mapper()
>>> 'a' in mapper
True
>>> 'b' in mapper
False
>>> mapper['a']
Retrieving 'a'
1

方案2:在__getitem__中处理序列遍历的情况(不推荐)

如果不想实现__contains__,可以在__getitem__中判断如果是整数索引,直接抛出IndexError,让Python停止序列遍历:

class Mapper:
    def __getitem__(self, key):
        print(f'Retrieving {key!r}')
        # 拦截整数索引,触发序列遍历终止逻辑
        if isinstance(key, int):
            raise IndexError
        if key == 'a':
            return 1
        else:
            raise KeyError('This only contains a')

这种方式可以让'a' in mapper返回False(因为遍历0时抛出IndexError),但不符合映射类型的设计逻辑,不推荐使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 00:35:26