有人能解释一下我代码最后 3 行中成员测试的行为吗,为什么它是 False? 为什么迭代器和可迭代对象的成员资格测试不同?
c = [1,2,3,4,5,6,7,8,9,10,11,12]
print(3 in c) # True
print(3 in c) # True
d = iter(c)
print(2 in d) # True
print(4 in d) # True
print(4 in d) # False ???
print(6 in d) # False ???
print(10 in d) # False ???
迭代器在使用时被消耗。我会解释你的例子:
>>> c = [1,2,3,4,5,6,7,8,9,10,11,12]
>>> d = iter(c)
>>> print(list(d))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
>>> print(list(d))
[]
您可以将迭代器
d
视为指向列表中第一项的指针。一旦您读取了它的值,它就会指向第二项。当它到达末尾时,它指向一个空列表。
另见:
>>> c = [1,2,3,4,5,6,7,8,9,10,11,12]
>>> d = iter(c)
>>> print(next(d))
1
>>> print(next(d))
2
>>> print(list(d))
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
检查里面是否有东西也会消耗它的内容:
>>> c = [1,2,3,4,5,6,7,8,9,10,11,12]
>>> d = iter(c)
>>> 4 in d
True
>>> print(list(d))
[5, 6, 7, 8, 9, 10, 11, 12]
这个问题看起来很陈旧,但最近,我正在用我自己的迭代器类做一些实验,这让我对成员检查的内部工作原理有了一些了解。这是说明正在发生的事情的代码。
import logging
logging.basicConfig(format='%(asctime)s|%(levelname)s: %(message)s',
datefmt='%H:%M:%S, %d-%b-%Y', level=logging.INFO)
class Iterator:
"""Customise the Iterator with logging messages."""
def __init__(self, max_value:int=20):
"""Initialise with a default state and a maximum value"""
self.max_value:int=max_value
self.value:int=-1
def __iter__(self):
"""Part of the usual iterator protocol."""
return self
def __next__(self)->int:
"""Part of the usual iterator protocol."""
logging.info(msg=f'Next was called with {self.value}')
self.value+=1
if self.value>self.max_value:raise StopIteration
return self.value
sample_iterator=Iterator()
3 in sample_iterator # Gives True
3 in sample_iterator # Gives False
第一次检查的日志输出
11:12:19, 19-May-2023|INFO: Next was called with -1
11:12:19, 19-May-2023|INFO: Next was called with 0
11:12:19, 19-May-2023|INFO: Next was called with 1
11:12:19, 19-May-2023|INFO: Next was called with 2
和下一次检查的输出
11:12:31, 19-May-2023|INFO: Next was called with 3
11:12:31, 19-May-2023|INFO: Next was called with 4
11:12:31, 19-May-2023|INFO: Next was called with 5
11:12:31, 19-May-2023|INFO: Next was called with 6
11:12:31, 19-May-2023|INFO: Next was called with 7
11:12:31, 19-May-2023|INFO: Next was called with 8
11:12:31, 19-May-2023|INFO: Next was called with 9
11:12:31, 19-May-2023|INFO: Next was called with 10
11:12:31, 19-May-2023|INFO: Next was called with 11
11:12:31, 19-May-2023|INFO: Next was called with 12
11:12:31, 19-May-2023|INFO: Next was called with 13
11:12:31, 19-May-2023|INFO: Next was called with 14
11:12:31, 19-May-2023|INFO: Next was called with 15
11:12:31, 19-May-2023|INFO: Next was called with 16
11:12:31, 19-May-2023|INFO: Next was called with 17
11:12:31, 19-May-2023|INFO: Next was called with 18
11:12:31, 19-May-2023|INFO: Next was called with 19
11:12:31, 19-May-2023|INFO: Next was called with 20
这就是我的结论。当您要求对元素进行成员资格检查时,迭代器开始从其当前状态计算
next
,直到它获得
True
False
更具体地说,
val:bool=elem in sample_iterator
相当于
val:bool
while True:
try:
current=next(sample_iterator)
except StopIteration:
val=False
break
if elem==current:
val=True
break
底线,成员资格测试是对迭代器的侵入式测试。不要在迭代器或任何您知道检查本身会改变内部状态的类上执行此测试。
因为迭代器有一个状态——在你的例子中是指向当前元素的指针。
两次顺序检查的区别
print(4 in d) # True
print(4 in d) # False ???
是迭代器的状态。首先检查迭代器的指针在 4.
之后设置为下一个元素