Python中in关键字和__contains__的区别

5

我想知道有人能否解释Python中“in”关键字和contains方法的区别。

我正在使用一个示例列表,并发现了这种行为。什么情况下应该使用这两个?如果我使用其中之一,是否可以实现更高的效率。

    >>> my_list = ["a", "b", "c"]
    >>> my_list.__contains__("a")
    True
    >>> "a" in my_list
    True

http://www.rafekettler.com/magicmethods.html - satoru
4个回答

8

__contains__() 方法是当你使用 in 语句时调用的对象方法。

对于列表,这是预定义的,但您也可以定义自己的类,添加一个 __contains__ 方法并在该类的实例上使用 in

您应该使用 in 而不是直接调用 __contains__()


5
文档中得知:
对于列表和元组类型,当且仅当存在索引i满足x==y[i]时,x in y为真。
对于字符串类型,当且仅当x是y的子串时,x in y为真。等效的测试方法是y.find(x) != -1。
对于定义了__contains__()方法的用户自定义类,当且仅当y.__contains__(x)为真时,x in y为真。
对于未定义__contains__()但定义了__iter__()方法的用户自定义类,在迭代y时产生某个值z使得x == z时,x in y为真。如果在迭代过程中引发异常,则好像in引发了该异常。
最后,尝试旧式迭代协议:如果一个类定义了__getitem__(),则当且仅当存在非负整数索引i满足x==y[i]且所有较低的整数索引不引发IndexError异常时,x in y为真。

2

和大多数魔术方法一样,__contains__ 方法并不是直接调用的。 __contains__ 存在的原因恰恰是为了让你可以写 obj in container 而不必使用方法调用语法。 因此,你应该使用 obj in container


1

在我的列表中执行"a" in my_list实际上调用了my_list__contains__方法(如果已定义)。

如果未定义__contains__,则使用__iter__,如果未定义__iter__,则使用__getitem__

__contains__是一种很好的方式,让某些容器或可迭代对象能够快速检查成员资格,而无需遍历整个序列,例如range()

>>> %timeit 10**5 in range(10**9)
159 ns ± 1.16 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)

https://docs.python.org/3/reference/expressions.html#membership-test-operations

对于定义了__contains__()方法的用户自定义类,如果y.__contains__(x)返回一个真值,x in y返回True,否则返回False
对于没有定义__contains__()但定义了__iter__()的用户自定义类,如果在迭代y时产生了某个值z,使得表达式x is z or x == z为真,则x in yTrue。如果在迭代过程中引发了异常,则就好像in引发了该异常。
最后,尝试使用旧式的迭代协议:如果一个类定义了`__getitem__()`方法,那么当且仅当存在非负整数索引`i`使得`x is y[i] or x == y[i]`成立,并且没有更小的整数索引会引发`IndexError`异常时,`x in y`的结果为`True`。(如果引发了其他异常,则视为引发了该异常)。

iter() 是什么意思?它会在什么时候被调用? - Mohammad Kholghi
1
@MohammadKholghi 这取决于类型。如果一个类没有定义__contains__,那么会使用__iter__来进行成员检查。当你循环遍历列表时,列表会使用__iter__返回一个特殊的list_iterator对象。 - Ashwini Chaudhary
1
https://docs.python.org/3/reference/expressions.html#membership-test-operations - Ashwini Chaudhary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接