イテレータとジェネレータは、Pythonにおけるシーケンスの効率的な処理の基礎です。歴史的に見ると、Pythonはデータストリームを扱う操作を簡素化し、大きなコレクションをメモリに無駄に保持することを避けることを目指してきました。最初に__iter__と__next__プロトコルを通じてイテレータのサポートが登場し、その後yield構文を基にした最もシンプルなイテレータを作成できるジェネレータが登場しました。
問題: 大量のデータ(例えば、ファイルやデータベースからのストリーミング)を処理する必要があることが多く、すべてを一度にメモリに読み込むことは便利でも効率的でもありません。通常の関数はすべての結果を一度に返しますし、クラスを通じて独自のイテレータを作成するのは、単純なケースでは過剰です。
解決策: yieldメカニズムにより、データの「遅延」生成を組織化できます。ジェネレータ関数はリストや他のコレクションを返すのではなく、必要に応じて値を計算するイテレータであるジェネレータオブジェクトを返します。
コード例:
# シンプルなジェネレータ def countdown(n): while n > 0: yield n n -= 1 for i in countdown(3): print(i) # 3, 2, 1
主な特徴:
returnとyieldを同じ関数内で使用できますか?
はい、できますが、ジェネレータ内のreturnはイテレーションを終了させ(StopIterationをスロー)、yieldは無制限に使用できます。
def example(): yield 1 return # StopIteration
なぜジェネレータは終了後に「再起動」できないのか?
ジェネレータがイテレーションを終了した後(StopIteration)、それを再起動することはできず、新しく作成する必要があります。
gen = countdown(2) list(gen) # [2, 1] list(gen) # [] (ジェネレータはすでに使い果たされています)
ジェネレータとイテレータの違いは何ですか?
ジェネレータはイテレータの特別なケースです; __iter__と__next__メソッドを持つ任意のオブジェクトはイテレータですが、ジェネレータはyieldを使って関数内で作成されます。
開発者は、分析のためにlist(fd)を通じてファイルの100万行をメモリに読み込む関数を書きました。これによりサーバーのメモリがオーバーフローしました。
利点:
欠点:
ファイルを行単位で読むためのジェネレータを使用し、yieldを用いたデータのリアルタイム分析を行います。
利点:
欠点: