ジェネレータ関数は yield を使って値を逐次生成します。大量のデータをメモリに載せずに処理できるため、効率的なイテレーション処理が可能です。
基本構文
def count_up(n): for i in range(n): yield i for num in count_up(5): print(num) # 0, 1, 2, 3, 4
yield に到達すると値を返して一時停止し、次の反復で再開します。
リストとの違い
# リスト:全要素をメモリに保持 def get_list(n): return [i for i in range(n)] # ジェネレータ:必要な時に生成 def get_generator(n): for i in range(n): yield i
100 万件のデータを処理する場合、リストはすべてをメモリに載せますが、ジェネレータは 1 件ずつ処理します。
ジェネレータ式
リスト内包表記と同様の構文で、丸括弧を使います。
gen = (x ** 2 for x in range(10)) print(next(gen)) # 0 print(next(gen)) # 1
yield from
別のイテラブルから値を委譲できます。
def flatten(nested): for item in nested: if isinstance(item, list): yield from flatten(item) else: yield item data = [1, [2, 3, [4, 5]], 6] print(list(flatten(data))) # [1, 2, 3, 4, 5, 6]
send と双方向通信
ジェネレータに値を送り込むこともできます。
def accumulator(): total = 0 while True: value = yield total if value is not None: total += value gen = accumulator() next(gen) # ジェネレータを起動 print(gen.send(10)) # 10 print(gen.send(20)) # 30
ジェネレータはメモリ効率の良いデータ処理、無限シーケンス、パイプライン処理などに活用できます。