嵌套for循环与while循环复用迭代器为何行为不同?
为什么嵌套for循环和while循环复用迭代器时行为不一样?
先看这段用嵌套for循环复用迭代器的Python代码:
from itertools import chain lst = ['a', 1, 2, 3, 'b', 4, 5, 'c', 6] def nestedForLoops(): it = iter(lst) for item0 in it: if isinstance(item0, str): print(item0) else: # this shouldn't happen because of # 1. lst[0] is a str, and # 2. line A print(f"this shouldn't happen: {item0=}") pass for item1 in it: if not isinstance(item1, int): break print(f'\t{item1}') else: # no-break # reached end of iterator return # reached a str assert isinstance(item1, str) it = chain(item1, it) # line A nestedForLoops()
预期输出:
a 1 2 3 b 4 5 c 6
但实际输出却是:
a 1 2 3 this shouldn't happen: item0=4 this shouldn't happen: item0=5 c this shouldn't happen: item0=6
换成嵌套while循环实现相同逻辑,输出就符合预期了:
from itertools import chain lst = ['a', 1, 2, 3, 'b', 4, 5, 'c', 6] def nestedWhileLoops(): it = iter(lst) while True: try: item0 = next(it) except StopIteration: break if isinstance(item0, str): print(item0) else: # this shouldn't happen because of # 1. lst[0] is a str, and # 2. line B print(f"this shouldn't happen: {item0=}") pass while True: try: item1 = next(it) except StopIteration: # reached end of iterator return if not isinstance(item1, int): break print(f'\t{item1}') # reached a str assert isinstance(item1, str) it = chain(item1, it) # line B nestedWhileLoops()
核心原因
差异的关键在于for循环对迭代器的绑定机制:
- 外层
for item0 in it在循环初始化时,就已经把迭代器对象固定绑定到循环内部了。后续你修改变量it让它指向chain(item1, it)生成的新迭代器,完全不会影响外层for循环正在使用的那个原始迭代器。 - 第一次循环时,外层for用原始迭代器拿到'a',内层for迭代原始迭代器拿到1、2、3,遇到'b'后break,接着你把
it改成了包含'b'的新迭代器,但外层for循环根本不关心这个新的it,它依然拿着原始迭代器继续迭代,下一次直接取原始迭代器里的下一个元素4,自然就触发了错误分支。
而while循环的逻辑是每次通过next(it)获取元素,当it被重新赋值为新的迭代器后,下一次调用next(it)就会使用这个新迭代器。所以当遇到'b'时,it被替换成包含'b'的迭代器,下次外层while的next(it)就会先拿到'b',完全符合预期逻辑。
内容的提问来源于stack exchange,提问作者joseville
相关产品推荐
相关产品推荐

