为什么在iterable上调用list()会改变它?

时间:2016-05-01 11:18:47

标签: python iterator iterable

考虑这段代码,我使用combinations并尝试列出一个列表。

from itertools import combinations

t = (1,2,3,4)
print("t is %r" % (t,))
print("list(t) is %r" % list(t))
print("list(t) is %r" % list(t))

t2 = ("a", "b", "c", "d")
print("t2 is %r" % (t2,))

combs = combinations(t2, 2)
print("List of combinations of t2: %r" % list(combs))
print("List of combinations of t2: %r" % list(combs))

输出(意外地为我)

t is (1, 2, 3, 4)
list(t) is [1, 2, 3, 4]
list(t) is [1, 2, 3, 4]
t2 is ('a', 'b', 'c', 'd')
List of combinations of t2: [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
List of combinations of t2: []

很明显,list()有副作用。 正如所料,将元组转换为列表不会更改原始数据,我可以多次执行此操作。但是当我尝试使用从combinations返回的迭代时,它只能运行一次,然后迭代看似无效。 list是否在迭代上调用next,以便在完成后,迭代器结束或为什么会发生这种情况? 我怎么能避免它?

2 个答案:

答案 0 :(得分:3)

library(devtools)生成一个惰性生成器,而不是一个保存在内存中的完整数据结构。一旦你用itertools.combinations之类的东西耗尽它(迭代它),那就......好吧,筋疲力尽。空。如果要重复使用它,请保存参考:

list()

答案 1 :(得分:0)

正如您所正确观察到的那样,list具有破坏性,因为生成器只能耗尽一次。一个简单的解决方案是使用itertools.tee

>>> c1, c2 = itertools.tee(itertools.combinations(["a", "b", "c"], 2))
>>> print(list(c1))
... will print the entire sequence of combinations
>>> print(list(c2))
... same as before

由于itertools.tee只需要保留所有迭代器都没有使用过的元素,因此保留整个列表可能更具内存保守性。