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 は1 回だけ反復できます。

代わりに、ループ内に新しいiterable を作成します。サイクルはそれを行うことはできません。渡されたものは何でも動作する必要があります。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 に答える