10

当我注意到我的简单实现没有产生正确的结果时,我正在写这个问题的答案。在寻找错误时,我注意到以下内容:

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)]

无论出于何种原因,gennext()方法被称为一个额外的时间。为了说明这一点,我使用了以下内容:

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)]
4

2 回答 2

17

发生这种情况是因为从左到右zip评估迭代器,这意味着,在三个步骤之后,它会调用并且只有然后才会调用(或类似的东西)并遇到 a 。为了解决这个问题,使用较短的(有限的)迭代作为最左边的参数:next()geniter(range(3))StopIteration

In [8]: zip(range(3), gen)
0
1
2
Out[8]: [(0, 0), (1, 1), (2, 2)]
于 2012-06-26T15:04:56.393 回答
7

您的自我回答完全正确,并提供了一个非常好的解决方案——如果其中一个论点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)]

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

于 2012-06-26T15:51:23.383 回答