Python yieldをマスター:ジェネレータvs return – 実践ガイド
Python yieldをマスター:ジェネレータvs return – 実践ガイド
yieldキーワードはreturnのように振る舞いますが、値を即座に返す代わりに、イテレーション可能なジェネレータオブジェクトを返します。yieldを含む関数が呼び出されると、最初のyield文で実行が一時停止し、ジェネレータとともに呼び出し元に制御が戻ります。その後next()やforループで再開すると、その地点から実行が続き、次の値がyieldされます。
重要なポイント
- yieldはジェネレータを作成し、遅延評価を可能にする
- ジェネレータは大規模または無限シーケンスでメモリ効率が良い
- ジェネレータからの読み取りは
for-in、list()、next()で可能 - 一度尽きたジェネレータは再利用不可;関数を再度呼び出す必要あり
構文
yield expression
実例: シンプルなyield
def test_yield():
yield "Welcome to Guru99 Python Tutorials"
output = test_yield()
print(output)
出力:
<generator object test_yield at 0x00000028265EB9A8>
ジェネレータオブジェクトがyieldされた値を保持します。アクセスするにはイテレーション:
for value in output:
print(value)
出力:
Welcome to Guru99 Python Tutorials
ジェネレータの説明
ジェネレータ関数は、イテラブルなジェネレータオブジェクトを返す特殊な関数です。単一の値を返す通常の関数とは異なり、ジェネレータは値のシーケンスを遅延生成し、要求されたときにのみ各値を生成します。
ジェネレータ関数の作成
def generator_example():
yield "H"
yield "E"
yield "L"
yield "L"
yield "O"
for letter in generator_example():
print(letter)
出力:
H E L L O
通常関数 vs ジェネレータ関数
以下の関数ペアを比較:
# 通常関数
def normal_test():
return "Hello World"
# ジェネレータ関数
def generator_test():
yield "Hello World"
print(normal_test()) # → Hello World
print(generator_test()) # → <generator object generator_test>
通常関数はreturnで終了;ジェネレータはyieldで一時停止し、ジェネレータオブジェクトとともに制御を呼び出し元に返します。
ジェネレータの消費
ジェネレータから値を取り出す方法:
for-inループ- 全値を実体化する
list() - 手動ステップ用の
next()
例: 偶数
def even_numbers(n):
for x in range(n):
if x % 2 == 0:
yield x
print(list(even_numbers(10))) # → [0, 2, 4, 6, 8]
for-in使用
for num in even_numbers(10):
print(num)
出力:
0 2 4 6 8
next()使用
gen = even_numbers(10)
for _ in range(6):
try:
print(next(gen))
except StopIteration:
print("ジェネレータ終了")
出力:
0 2 4 6 8 ジェネレータ終了
ジェネレータは一回限り
ジェネレータが完全にイテレーションされると尽きます。再イテレーションしても何も生成されず、ジェネレータ関数を再度呼び出す必要があります。
gen = even_numbers(10)
for num in gen:
print(num)
print(list(gen)) # → []
yieldの実例: フィボナッチ数列
def fibonacci_series(limit):
a, b = 0, 1
count = 0
while count < limit:
yield a
a, b = b, a + b
count += 1
fib = fibonacci_series(7)
for num in fib:
print(num)
出力:
0 1 1 2 3 5 8
yieldする関数の呼び出し
ヘルパー関数と各結果をyieldするジェネレータで数値を2乗:
def square(n):
return n * n
def square_range(n):
for i in range(n):
yield square(i)
for value in square_range(10):
print(value)
出力:
0 1 4 9 16 25 36 49 64 81
yieldをreturnより選ぶべき時
- 一度に全アイテムを読み込むのが非現実的な大規模またはストリーミングデータの処理
- 潜在的に無限のシーケンス生成(遅延ファイルリーダーなど)
- 大規模データセットのメモリフットプリントと起動時間の改善
- 最終値を返すだけでなく、計算を一時停止・再開する必要がある場合
yield vs return – クイックリファレンス
| yield | return |
|---|---|
| ジェネレータを返す;イテレーションで実行再開 | 関数終了;単一値を即座に返す |
各yieldで一時停止、メモリ節約 | 戻り値分のメモリ確保 |
| 大規模・無限シーケンスに最適 | 小規模・離散的結果に適する |
| 大規模データセットで実行時間高速 | 巨大データ処理でオーバーヘッド発生可能 |
重要なポイント
- yieldは値ではなくジェネレータオブジェクトを生成
- ジェネレータは値を遅延配信し、メモリ使用量を最小限に
for-in、list()、next()で値を読み取り- 尽きたジェネレータは再作成が必要
- 大規模・ストリーミングデータではyieldがreturnより高性能
Python
- Python ラムダ関数: 無名関数の実践ガイド
- Pythonジェネレータ:効率的イテレーションと高度なユースケース
- Pythonクロージャ解説:ネスト関数が変数を捕捉する仕組み
- Pythonデコレータマスター:エキスパート技法で関数を拡張
- Python strip()メソッド完全ガイド:実践例付き
- Python len()関数:オブジェクトの長さを測る実践ガイド
- Pythonラムダ関数をマスターする:実例とベストプラクティス
- Python round()関数を実例で徹底解説
- Python map()関数をマスター:構文、例、ベストプラクティス
- Python collections.Counter:効率的なカウント、更新、演算操作
- Python enumerate()をマスター:リスト、タプル、文字列、辞書でインデックス付きループ