跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

Python itertools.tee函数:为什么多个迭代器并非总是完全独立?

itertools.tee
的非完全独立性 Python 的
itertools.tee
函数旨在从单个迭代器创建多个独立的迭代器副本。然而,这些副本并非总是完全独立的,尤其是在处理生成器等惰性迭代器时。 关键在于
tee
创建的迭代器共享底层迭代器的状态,而非完全复制其数据。 让我们分析以下代码:
from itertools import tee def func(): g = (x for x in range(3, 100, 2)) # 生成器,产生奇数 while True: n = next(g) yield n g = filter(lambda x: x % n > 0, g) # 筛选掉n的倍数 g1, g2 = tee(g, 2) # 关键部分:对g1迭代,影响g和g2 for i in range(10): next(g1) g = g2 # g2 继承了被g1消耗后的状态 g = func() print([next(g) for i in range(10)])
问题根源:共享状态与惰性求值 立即学习 “ Python免费学习笔记(深入) ”; 代码中的
g
是一个生成器,它按需产生奇数。
tee(g, 2)
创建了两个迭代器
g1
g2
,它们都指向同一个
g
。 关键在于
filter
函数:它并没有预先计算所有结果,而是惰性地根据需要进行筛选。 Python 3.14.3 微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。 下载 当
for
循环迭代
g1
十次时,
g1
g
中获取元素并进行筛选。由于
g1
g2
g
共享底层生成器的状态,
g
本身的状态也在被修改(筛选掉已处理的数的倍数)。 因此,
g2
继承了这个被修改后的状态,导致其产生的序列与预期不同。 解决方法:避免在其他地方使用原始迭代器 Python 文档明确指出,在使用
tee
后,应避免再次使用原始迭代器 (
g
在本例中)。 因为对原始迭代器的任何操作都会影响
tee
创建的迭代器。 为了获得预期的结果,应该修改代码,避免对
g
进行任何进一步操作,只使用
tee
创建的迭代器
g1
g2
from itertools import tee def func(): g = (x for x in range(3, 100, 2)) while True: n = next(g) yield n g = filter(lambda x: x % n > 0, g) g1, g2 = tee(g, 2) g = g2 # 这里不再使用g1 # for i in range(10): # 去除这部分循环 # next(g1) g = func() print([next(g) for i in range(10)]) # 输出:[3, 5, 7, 11, 13, 17, 19, 23, 29, 31]
通过移除
for
循环并只使用
g2
,我们消除了对原始生成器
g
的额外操作,从而保证了
tee
创建的迭代器的独立性,得到预期的素数序列。

相关文章