在 Python 中,in 运算符是如何实现工作的?它是否使用迭代器的 next() 方法?



在 Python 中,众所周知,检查迭代器(列表、字典等)中的成员资格并在字符串中查找子字符串。我的问题是关于如何实现in以实现以下所有目标:1) 测试成员资格,2) 测试子字符串和 3) 访问 for 循环中的下一个元素。 例如,当执行for i in myList:if i in myList:时,是否调用myList.__next__()?如果它确实调用了它,那么它如何处理字符串,因为str对象不是迭代器(如 Python 2.7 中检查的那样),因此没有next()方法?如果无法详细讨论in的实现,如果在此处提供它的要点,将不胜感激。

类可以通过定义__contains__方法来定义in运算符在该类的实例上的工作方式。

Python 数据模型文档说:

对于没有定义__contains__()的对象,成员资格测试首先通过__iter__()尝试迭代,然后通过__getitem__()尝试旧的序列迭代协议,请参阅语言参考中的这一部分。

Python 语言参考的第 6.10.2 节 "成员资格测试操作"是这样说的:

操作员innot in成员资格测试。x in s计算结果为Truex是否是s的成员,否则Falsex not in s返回x in s的否定。所有内置序列和集合类型都支持此功能以及字典,in字典测试字典是否具有给定键。对于容器类型(如列表、元组、集合、冻结集、字典或集合.deque),表达式x in y等效于any(x is e or x == e for e in y)

对于字符串和字节类型,当且仅当xy的子字符串时,x in yTrue。等效测试是y.find(x) != -1。空字符串始终被视为任何其他字符串的子字符串,因此"" in "abc"将返回True

对于定义__contains__()方法的用户定义类,如果返回 truey.__contains__(x)值,则x in y返回True,否则False返回。

对于不定义__contains__()但定义__iter__()的用户定义类,如果在迭代y时产生一些与x == zz的值,则x in yTrue。如果在迭代期间引发异常,就好像in引发该异常一样。

最后,尝试旧式迭代协议:如果一个类定义了__getitem__(),则当且仅当存在非负整数索引i使得x == y[i]并且所有较低的整数索引不会引发IndexError异常时,x in yTrue。(如果引发任何其他异常,就好像in引发了该异常)。

运算符not in定义为具有in的反真值。

如上文注释所示,表达式运算符in不同于构成for语句一部分的关键字in。在 Python 语法中,in被"硬编码"为for语法的一部分:

for_stmt ::=  "for" target_list "in" expression_list ":" suite
["else" ":" suite]

因此,在for语句的上下文中,in的行为不是运算符,它只是将target_listexpression_list分开的语法标记。

Python 有__contains__特殊方法,当你执行item in collection时会使用。

例如,下面是一个"__contains__"所有偶数的类:

>>> class EvenNumbers:
...   def __contains__(self, item):
...     return item % 2 == 0
...
>>> en = EvenNumbers()
>>> 2 in en
True
>>> 3 in en
False
>>>

最新更新