Python __getitem__ 和 in 运算符导致奇怪的行为

Mat*_*sen 34 python python-3.x

什么解释了以下行为:

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
Run Code Online (Sandbox Code Playgroud)

use*_*ica 45

如果一个对象没有__contains__实现,则in返回到一个基本上像这样工作的默认值:

def default__contains__(self, element):
    for thing in self:
        if thing == element:
            return True
    return False
Run Code Online (Sandbox Code Playgroud)

如果一个对象没有__iter__实现,则for返回到一个基本上像这样工作的默认值:

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

即使对象不是一个序列,也会使用这些默认值。

1 in f5 in f测试使用的是默认的回退infor,导致观察到的行为。立即1 in f找到1,但您__getitem__永远不会返回5,因此5 in f永远运行。

(嗯,实际上,在 Python 的参考实现中,默认__iter__回退将索引存储在 C 级变量中Py_ssize_t,因此如果您等待的时间足够长,该变量将达到最大值并且Python 会引发一个 OverflowError。如果您看到了,您必须在 32 位 Python 版本上。计算机的存在时间还不够长,任何人都无法在 64 位 Python 上使用它。)

  • @MatthewMoisen:这些默认值是“for”和“in”的原始行为,早于“__iter__”和“__contains__”的引入。请参阅Python 1.4文档[此处](https://docs.python.org/release/1.4/ref/ref5.html#HDR16)和[此处](https://docs.python.org/release/1.4/参考/ref7.html#HDR2)。 (4认同)
  • @Matthew [表达式>成员测试操作](https://docs.python.org/3/reference/expressions.html#membership-test-details),还有[object.__contains__](https://docs.python. org/3/reference/datamodel.html#object.__contains__) 及其上方的段落 (3认同)