11

Python 的 itertools.cycle() 的文档给出了一个伪代码实现:

def cycle(iterable):
    # cycle('ABCD') --> A B C D A B C D A B C D ...
    saved = []
    for element in iterable:
        yield element
        saved.append(element)
    while saved:
        for element in saved:
              yield element

下面,它指出:“注意,工具包的这个成员可能需要大量的辅助存储(取决于可迭代的长度)。”

我基本上是沿着这条路走的,除了我这样做了,它不需要创建可迭代的副本:

def loop(iterable):
    it = iterable.__iter__()

    while True:
        try:
            yield it.next()
        except StopIteration:
            it = iterable.__iter__()
            yield it.next()

x = {1, 2, 3}

hard_limit = 6
for i in loop(x):
    if hard_limit <= 0:
        break

    print i
    hard_limit -= 1

印刷:

1
2
3
1
2
3

是的,我意识到我的实现不适用于 str,但可以做到。我更好奇为什么它会创建另一个副本。我感觉它与垃圾收集有关,但我在 Python 的这个领域没有深入研究。

谢谢!

4

1 回答 1

17

Iterables 只能迭代一次

您可以在循环中创建一个新的可迭代对象。Cycle 无法做到这一点,它必须与您传入的任何内容一起工作。cycle不能简单地重新创建可迭代对象。因此,它被迫存储原始迭代器产生的所有元素。

如果您要传入以下生成器,则会loop()失败:

def finite_generator(source=[3, 2, 1]):
    while source:
        yield source.pop()

现在你的loop()产品:

>>> hard_limit = 6
>>> for i in loop(finite_generator()):
...     if hard_limit <= 0:
...         break
...     print i
...     hard_limit -= 1
... 
1
2
3

您的代码仅适用于序列,对于这些序列,使用cycle()将是多余的;cycle()在这种情况下,您不需要存储负担。将其简化为:

def loop_sequence(seq):
    while True:
        for elem in seq:
            yield elem
于 2013-05-19T19:35:42.510 回答