如何解释以下行为:

class Foo:
    def __getitem__(self, item):
        print("?")
        return 1

f = Foo()

1 in f  # prints one ? and returns True

5 in f  # prints ? forever until you raise a Keyboard Exception

# Edit: eventually this fails with OverflowError: iter index too large

推荐答案

如果一个对象没有__contains__实现,in会使用基本如下的默认值:

def default__contains__(self, element):
    for thing in self:
        if thing == element:
            return True
    return False

如果一个对象没有__iter__实现,for会使用默认值,基本上是这样工作的:

def default__iter__(self):
    i = 0
    try:
        while True:
            yield self[i]
            i += 1
    except IndexError:
        pass

即使对象不打算成为序列,也会使用这些默认值.

您的1 in f5 in f测试正在使用infor的默认回退,从而导致观察到的行为.1 in f立即找到1,但你的__getitem__永远不会返回5,所以5 in f永远运行.

(事实上,在Python的参考实现中,默认的__iter__回退将索引存储在Py_ssize_t类型的C级变量中,因此如果等待足够长的时间,该变量将达到最大值Python raises an OverflowError.如果你看到了这一点,你必须使用32位Python构建.计算机的存在时间还不足以让任何人在64位Python上实现这一点.)

Python-3.x相关问答推荐

Django 3.2/Django-cms 3.11:查找错误:型号帐户.客户用户未注册

PySpark每毫秒使用先前的值填充数据

如何计算累积几何平均数?

Python VS Code 自动导入路径包含 src

在python内的powershell中转义$_

PyQt5 中耦合滑块和拨号小部件.解决结果不一致的问题

为什么 get_form 方法中小部件的更改没有反映 Django 管理站点中的更改

Django在POST到外部URL时如何进行CSRF保护? 更新

删除列表中的第二个出现

转换Pandas 数据框 - 添加行

如何对具有多个列值的 pandas 数据框进行数据透视/数据透视表

当参数名称与 typing.Protocol 中定义的名称不同时发生 mypy 错误

如何使用`re.findall`从字符串中提取数据

列表中的重复数字与列表理解

ValueError:找不到子字符串,我做错了什么?

smtplib 在 Python 3.1 中发送带有 unicode 字符的邮件的问题

为什么不切换到 Python 3.x?

通过多个键对字典列表进行分组和聚合

如何强制 Sphinx 使用 Python 3.x 解释器

TypeError:无法实例化类型元组;使用 tuple() 代替