【发布时间】:2018-11-09 00:34:03
【问题描述】:
我正在尝试使用 itertools.tee 来知道迭代器是否为空而不完全消耗它:
from itertools import tee
def get_iterator(i):
i1, i2 = tee(i, 2)
if next(i1, None) is None:
# iterator is empty - raises some error
pass
return i2 # return not empty iterator to caller
正如 tee 的 docs 所说:
此迭代工具可能需要大量辅助存储(取决于需要存储多少临时数据)。一般来说,如果一个迭代器在另一个迭代器启动之前使用了大部分或全部数据,那么使用 list() 而不是 tee() 会更快。
所以很明显,当 i 不为空时,i2 在 i1 之前使用了大部分数据。 一个简单的 del 可以解决这个问题吗?:
from itertools import tee
def get_iterator(i):
i1, i2 = tee(i, 2)
if next(i1, None) is None:
# iterator is empty - raises some error
pass
del i1 # Does this overcome storage issue?
return i2 # return not empty iterator to caller
有没有更好的方法来实现这个目标?
提前致谢!
【问题讨论】:
-
@Chris_Rands tee 基本上确实耗尽了整个迭代器来创建新的迭代器——这完全不是真的。
-
@Chris_Rands 文档说“以下 Python 代码有助于解释 tee 的作用(尽管实际实现更复杂,并且仅使用单个底层 FIFO 队列)。”如果您查看 CPython 代码中的
teedataobject_getitem,您会发现它仅在前导迭代器到达该点时才获取新数据PyIter_Next。然后它会存储该值,直到所有tees 都使用了该值。 -
查看 Alex Martelli 关于标记值 here 的评论。
-
@Chris_Rands 仅当您运行新迭代器之一时。例如,如果您使用
a, b, c = tee(itr, 3),那么如果您使用i = next(a); del i,您将在内存中存储i,直到next(b)和next(c)都被执行。最坏的情况是,如果您执行la = list(a),那么您将在内存中拥有len(la)元素,直到b和c都向前迭代。