什么也没有wrong从协议角度或理论上来说,这会阻止您编写此类代码。一个耗尽的迭代器it
会扔StopIteration
在随后的每次调用中it.__next__
, 所以for
从技术上讲,循环不会介意你用一个迭代器耗尽迭代器next
/__next__
在循环体中调用。
我建议不要编写这样的代码,因为该程序将很难推理。如果场景比您在这里展示的更复杂一些,至少我必须用笔和纸进行一些输入并弄清楚发生了什么。
事实上,假设您想要打印偶数前面的每个数字,您的代码片段的行为可能甚至不像您想象的那样。
>>> b = [1, 2, 4, 7, 8]
>>> a = iter(b)
>>> for x in a:
...: if x%2 == 0:
...: print(next(a, 'stop'))
4
stop
Why is 7
尽管前面有偶数,但已跳过4
?
>>>> a = iter(b)
>>>> for x in a:
...: print('for loop assigned x={}'.format(x))
...: if x%2 == 0:
...: nxt = next(a, 'stop')
...: print('if popped nxt={} from iterator'.format(nxt))
...: print(nxt)
...:
for loop assigned x=1
for loop assigned x=2
if popped nxt=4 from iterator
4
for loop assigned x=7
for loop assigned x=8
if popped nxt=stop from iterator
stop
事实证明x = 4
从未被分配for
循环,因为显式next
调用之前从迭代器中弹出该元素for
循环有机会再次查看迭代器。
这是我在阅读代码时不想弄清楚的细节。
如果你想迭代“中的可迭代对象(包括迭代器)(element, next_element)
“ 成对使用pairwise
recipe https://docs.python.org/3/library/itertools.html#itertools-recipes来自itertools
文档。
from itertools import tee
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
Demo:
>>> b = [1,2,3,4,5,6,7]
>>> a = iter(b)
>>>
>>> for x, nxt in pairwise(a): # pairwise(b) also works
...: print(x, nxt)
1 2
2 3
3 4
4 5
5 6
6 7
一般来说,itertools
与其食谱一起提供了许多强大的抽象,用于编写可读的迭代相关代码。更多有用的帮助器可以在more_itertools https://pypi.org/project/more-itertools/模块,包括一个实现pairwise https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.pairwise.