为什么zip()会丢弃我的生成器的值?

时间:2012-06-26 15:04:56

标签: python

当我注意到我的简单实现没有产生正确的结果时,我正在写this question的答案。在追捕这个bug时,我注意到了以下内容:

In [1]: import itertools
In [2]: gen = itertools.cycle((0,1,2))

In [3]: zip(gen, range(3))
Out[3]: [(0, 0), (1, 1), (2, 2)]

In [4]: zip(gen, range(3))
Out[4]: [(1, 0), (2, 1), (0, 2)]

无论出于何种原因,gen的{​​{1}}方法称为一个额外的时间。 为了说明这一点,我使用了以下内容:

next()

2 个答案:

答案 0 :(得分:17)

这是因为zip评估迭代器from left to right,这意味着,经过三个步骤,它会在next()上调用gen,然后才会调用iter(range(3))(或类似的东西)并遇到StopIteration。要解决这个问题,请使用较短的(有限)迭代作为最左边的参数:

In [8]: zip(range(3), gen)
0
1
2
Out[8]: [(0, 0), (1, 1), (2, 2)]

答案 1 :(得分:7)

Your self-answer完全正确,并且提供了一个非常好的解决方案 - 如果 zip的一个参数总是比另一个短。但是,在您不知道哪个更短的情况下,您可能会发现islice有用。如果您希望元组中的第一项来自您的生成器,islice也提供了一种简单的解决方法。在您的情况下,您可以这样做:

>>> import itertools
>>> gen = itertools.cycle(('a', 'b', 'c'))
>>> seq = range(3)
>>> zip(itertools.islice(gen, len(seq)), seq)
[('a', 0), ('b', 1), ('c', 2)]
>>> zip(itertools.islice(gen, len(seq)), seq)
[('a', 0), ('b', 1), ('c', 2)]

在这种情况下你的答案可能更好 - 它肯定更简单 - 但我想我会把它作为补充。