Pythonジェネレータ:効率的イテレーションと高度なユースケース
Pythonジェネレータ
Pythonジェネレータが如何にイテレーションを簡素化し、ボイラープレートを削減し、従来のイテレータよりメモリ使用量を改善するかを学びます。
ジェネレータとは?
Pythonでカスタムイテレータを構築するには通常、__iter__()と__next__()を実装し、内部状態を管理し、終了時にStopIterationを発生させるクラスが必要です。ジェネレータは、値を1つずつ生成するシンプルな関数を書くだけでこのボイラープレートを排除します。
簡単に言えば、ジェネレータはイテレータを返す関数です。関数本体は遅延実行され、各yieldで一時停止し、以降の呼び出しで再開します。
Pythonでのジェネレータ作成
ジェネレータ定義は通常関数と同様で、returnをyieldに置き換えるだけ:
def my_gen():
n = 1
print('This is printed first')
yield n
n += 1
print('This is printed second')
yield n
n += 1
print('This is printed at last')
yield n
my_gen()呼び出しはイテレータを返し、next()呼び出し時に初めて実行開始します。
a = my_gen()
next(a) # 最初のメッセージ表示、1を返す
next(a) # 2番目のメッセージ表示、2を返す
next(a) # 最後のメッセージ表示、3を返す
next(a) # StopIteration発生
ローカル変数はyield間で持続しますが、ジェネレータは1回のみイテレーション可能。再開するには新インスタンス作成が必要。
ジェネレータはイテレータなので直接ループ可能:
for item in my_gen():
print(item)
一般的なジェネレータパターン
文字列反転
def rev_str(s):
for i in range(len(s)-1, -1, -1):
yield s[i]
for char in rev_str('hello'):
print(char)
リスト、タプルなど任意のイテラブルで動作。
ジェネレータ式
リスト内包表記と同様に、括弧で無名ジェネレータ作成可能:
my_list = [1, 3, 6, 10]
# リスト内包表記
squares_list = [x**2 for x in my_list]
# ジェネレータ式
squares_gen = (x**2 for x in my_list)
print(squares_list)
print(squares_gen)
ジェネレータはオンデマンドで値生成:
a = (x**2 for x in my_list)
print(next(a)) # 1
print(next(a)) # 9
print(next(a)) # 36
print(next(a)) # 100
next(a) # StopIteration
ジェネレータ式はsumやmaxなどの関数に直接渡せます(外側の括弧不要)。
なぜジェネレータを使うのか?
- 簡潔な実装:冗長なイテレータクラスを数行のコードで置換。
- メモリ効率:1アイテムずつ生成、大規模/無限シーケンスに最適。
- 無限ストリーム:尽きないデータソース表現可能(
while True: yield)。 - パイプライン合成:複数ジェネレータを連結し、クリーンで可読なデータ処理を実現。
例:2の累乗
def pow_two_gen(max_n=0):
n = 0
while n < max_n:
yield 2 ** n
n += 1
例:フィボナッチ数の平方和
def fibonacci_numbers(count):
a, b = 0, 1
for _ in range(count):
a, b = b, a + b
yield a
def square(nums):
for n in nums:
yield n ** 2
print(sum(square(fibonacci_numbers(10)))) # 4895
ジェネレータは幅広いイテレーションシナリオでエレガント、効率的、保守しやすいコードを可能にします。
Python
- Python 演算子完全マスター: 包括的ガイド
- Python 関数引数完全マスター: 位置引数・キーワード引数・デフォルト引数
- Python辞書完全ガイド:作成、操作、高度なテクニック
- Pythonジェネレータ:効率的イテレーションと高度なユースケース
- Pythonクロージャ解説:ネスト関数が変数を捕捉する仕組み
- Pythonデコレータマスター:エキスパート技法で関数を拡張
- Pythonラムダ関数をマスターする:実例とベストプラクティス
- Python abs()関数:数値と複素数の絶対値を計算
- Python round()関数を実例で徹底解説
- Python map()関数をマスター:構文、例、ベストプラクティス
- Python yieldをマスター:ジェネレータvs return – 実践ガイド