问题描述
>>> non_iterable = 1
>>> 5 in non_iterable
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: 'int' object is not iterable
>>> class also_non_iterable:
... def __contains__(self,thing):
... return True
>>> 5 in also_non_iterable()
True
>>> isinstance(also_non_iterable(), Iterable)
False
是否有一个原因in
关键字号称要一个迭代对象时,它真正想要的是实现一个对象__contains__
?
1楼
它声称需要一个可迭代的,因为如果对象的类没有实现__contains__
,那么in
尝试迭代对象并检查值是否等于它的值。
举例说明 -
>>> class C:
... def __iter__(self):
... return iter([1,2,3,4])
>>>
>>> c = C()
>>> 2 in c
True
>>> 5 in c
False
这在有解释
为它定义了用户定义的类
__contains__()
方法,x in y
,如果仅当且为真y.__contains__(x)
是真实的。对于没有定义
__contains__()
但是定义__iter__()
用户定义的类,如果在迭代y
产生一些带有x == z
值z
,则x in y
为真。 如果在迭代期间引发异常,则就好像在异常中引发异常一样。
2楼
是否有一个原因
in
关键字号称要一个迭代对象时,它真正想要的是实现一个对象__contains__
?
x in thing
for x in thing
中的for x in thing
是非常密切相关的。
几乎所有支持x in thing
遵循规则,即当for循环的thing
将找到一个等于x
的元素时x in thing
中的x in thing
为真。
特别是,如果一个对象支持迭代但不__contains__
,Python将使用迭代作为后备in
测试。
错误消息可能会说它需要__contains__
,但这与当前消息一样错误,因为__contains__
不是绝对必要的。
它可以说它需要一个容器,但它不能立即清楚什么算作一个容器。
例如,http://stardict.sourceforge.net/Dictionaries.php下载支持in
,但美其名曰容器是值得商榷的。
当前消息表示它需要可迭代,与其他选项一样准确。
它的优点是,在实践中,“是迭代”是一个更好的检查比“是它的容器”或“它支持__contains__
”确定实际的对象是否支持in
。
3楼
in
有两种不同的用途:
-
测试容器是否有值(例如,左参数实现
__contains__
) -
遍历一个序列(例如,右参数是
Iterable
)