itertools の python ドキュメントでは、イテレータを n ステップ進めるための次の「レシピ」を提供しています。
def consume(iterator, n):
"Advance the iterator n-steps ahead. If n is none, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)
なぜこのレシピがこのようなものと根本的に異なるのか疑問に思っています (イテレータ全体を消費する処理は別として):
def other_consume(iterable, n):
for i in xrange(n):
next(iterable, None)
私はtimeit
、予想通り、上記のアプローチがはるかに遅いことを確認していました。この優れたパフォーマンスを可能にするレシピで何が起こっているのでしょうか? を使用していることがわかりますislice
が、 を見るとislice
、上記のコードと基本的に同じことをしているように見えます。
def islice(iterable, *args):
s = slice(*args)
it = iter(xrange(s.start or 0, s.stop or sys.maxint, s.step or 1))
nexti = next(it)
### it seems as if this loop yields from the iterable n times via enumerate
### how is this different from calling next n times?
for i, element in enumerate(iterable):
if i == nexti:
yield element
nexti = next(it)
注:islice
からインポートする代わりにitertools
、上記のドキュメントの同等の Python を使用して定義しても、レシピはまだ高速です..
編集:timeit
ここにコード:
timeit.timeit('a = iter([random() for i in xrange(1000000)]); consume(a, 1000000)', setup="from __main__ import consume,random", number=10)
timeit.timeit('a = iter([random() for i in xrange(1000000)]); other_consume(a, 1000000)', setup="from __main__ import other_consume,random", number=10)
other_consume
これを実行するたびに〜2.5倍遅くなります