当我注意到我的简单实现没有产生正确的结果时,我正在写这个问题的答案.在追捕这个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)]
Run Code Online (Sandbox Code Playgroud)
无论出于何种原因,gen的next()方法被称为一个additioinal时间.为了说明这一点,我使用了以下内容:
class loudCycle(itertools.cycle):
def next(self):
n = super(loudCycle, self).next()
print n
return n
In [6]: gen = loudCycle((0,1,2))
In [7]: zip(gen, range(3))
0
1
2
0
Out[7]: [(0, 0), (1, 1), (2, 2)]
Run Code Online (Sandbox Code Playgroud)
Lev*_*sky 17
发生这种情况是因为从左到右zip评估迭代器,这意味着,在三个步骤之后,它会调用on ,然后才启动(或类似的东西)并遇到一个.要解决这个问题,请使用较短的(有限)迭代作为最左边的参数:next()geniter(range(3))StopIteration
In [8]: zip(range(3), gen)
0
1
2
Out[8]: [(0, 0), (1, 1), (2, 2)]
Run Code Online (Sandbox Code Playgroud)
你的自我回答是完全正确的,并提出了一个非常好的解决方案 - 如果其中一个参数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)]
Run Code Online (Sandbox Code Playgroud)
在这种情况下你的答案可能更好 - 它当然更简单 - 但我想我会补充这个.