「リクエストに応じた計算」または遅延計算は、処理されるデータの量が増えるにつれて人気を集めてきました。Pythonでは、標準ライブラリでジェネレーターとイテレーターを介して、後にitertools関数や一度に一要素を返すクラスを通じてこのメカニズムが実装されています。これにより、すべてのデータを一度にメモリに保持することを避けられます。
通常のコレクションの構築は、全ての結果をメモリに読み込む必要があります。データ量が多いと、プログラムが「クラッシュ」したり非常に遅く動作することがあります。データストリームを処理できることが重要です—例えば、数ギガバイトのファイルやAPIリクエストの結果など。
遅延計算では、必要に応じて要素を取得することができます。Pythonでは、ジェネレーター、yield構文、ジェネレーター式、map、filter、zip関数、およびitertoolsモジュールを使用することによってこのプロセスが簡素化されます。このアプローチは、イテレーターのプロトコルに基づいています。
コード例:
def huge_sequence(): for i in range(1, 10**9): yield i * i for val in huge_sequence(): if val > 100: break print(val)
主な特徴:
Pythonのジェネレーターは常にメモリを節約しますか?
回答: いいえ、データが実際にステップ間に中間保存を必要としない場合のみです。一部の構文、たとえばリスト内包表記は、全てのリストを一度に生成し、ジェネレーターは要求に応じてのみ生成します。中間結果が必要な場合、節約は失われます。
例:
squares = (x**2 for x in range(10**8)) # 遅延評価、節約 result = list(squares) # 一瞬で全てのメモリを消費
mapとfilterは常にリストを返しますか?
いいえ、Python 3ではmapとfilterはリストではなく、イテレーター(遅延ジェネレーター)を返します。これにより、メモリが節約され、データを「その場で」処理することが可能になります。
ジェネレーターを再度イテレートすることはできますか?
いいえ、ジェネレーターは完全にイテレートされた後、「消耗」します。再度イテレートが必要な場合は、新しいジェネレーターを作成するか、その内容を何度もイテレートできるコンテナコレクションを使用する必要があります。
list()、sum()、len());開発者が大きなログファイルを処理しようとして、行のリストとしてメモリに読み込もうとします。
利点:
欠点:
ジェネレーターが使用され、ファイルを行単位で読み込み、取得しながら各行を処理します。
利点:
欠点: