当サイトは、アフィリエイト広告を利用しています
Pythonの反復処理は、一見すると for 文だけで完結しているように見える。
for x in data:print(x)
しかし内部では、明確な構造の上に成り立っている
これらは別物であり、役割も異なる。
本記事では特に イテレータ に焦点を当て、
を整理する。
なお、上記の違いについては
で解説しているまず前提として、for 文は内部的に次のように動作している。
it = iter(obj)while True:try:value = next(it)except StopIteration:break
つまり反復の本質は
iter() でイテレータを取得next() で1要素ずつ取り出すStopIteration で終了である。
Pythonではfor 文はあくまで糖衣構文にすぎない。
イテレータとは、
である。
重要なのは、
という点である。
Pythonのいろんな記事を読んでいると
イテレータと遅延評価はセットと思われがちだが
結論から言うと、
イテレータは単に「順に値を返す」だけの仕組みであり、
は実装次第である。
data = [1, 2, 3]it = iter(data)
next(it) は既存の値を返すだけこれは遅延評価ではない。
リストを作成した時点で全要素がメモリに展開されており
イテレータは値を取り出しているだけ
gen = (x * 2 for x in [1, 2, 3])
next(gen)
が呼ばれた瞬間に初めて評価される。
これは遅延評価である。
つまり、遅延評価はイテレータという言葉では決まらない。
評価タイミングは、
の組み合わせで決まる。
実装サンプルを使って動作を解説する
result = [x * 2 for x in [1, 2, 3]]
gen = (x * 2 for x in [1, 2, 3])next(gen)
リストは既に全要素生成済みであるが
計算方法(実行ロジック)は遅延されている
next()が実行されて初めて評価される
gen = (x * 2 for x in range(10**9))next(get)
→ データ取得と評価がともに逐次実行
より完全な遅延構造になる。
ジェネレータは、
という実行モデルを持つ。
このモデルが、
という逐次実行を可能にしている。
遅延評価を実現する最も自然な仕組みがジェネレータである。
ジェネレータについては下記記事で詳しく解説している
Pythonは
を分離している。
この分離により、
つまり、
なのである。
イテレータとは
である。
遅延評価そのものではない。
遅延かどうかは、
の組み合わせで決まる。