Pythonのyieldを使ったジェネレーター関数の動作と活用方法をわかりやすく解説

スポンサーリンク
スポンサーリンク

yieldの概要

ジェネレーター関数の中断と再開 Python予約語

yield

概要 yield は、ジェネレーター関数の中で使用され、関数の実行を一時停止し、値を返しつつ状態を保持するためのキーワードです。通常の return とは異なり、次回呼び出されたときに処理を再開できます。

わかりやすく説明 yield は「少しずつ処理を進める」ための仕組みです。たとえば、巨大なデータセットを一度に処理するのではなく、必要なときに1つずつ取得できます。

  • yield を使うと、関数の状態を保持しつつ、一時停止と再開が可能。
  • 大規模データを効率的に処理する際に有用。
  • 通常の関数とは異なり、呼び出し時にジェネレーターオブジェクトを返す。

yieldの基本的な使い方

以下の例では、ジェネレーター関数を定義し、yield を使って値を順番に返します。

# yield を使ったジェネレーター関数
def count_up():
    for i in range(3):
        yield i  # ここで一時停止し、値を返す

gen = count_up()
print(next(gen))  # 0
print(next(gen))  # 1
print(next(gen))  # 2
  • yield i により、一度に 1 つの値を返す。
  • next() を呼び出すたびに、前回の状態を保持しつつ次の処理を実行。

ジェネレーターの動作

ジェネレーターは、next() を使うたびに1つずつ処理を進めます。

# next() の挙動
def simple_generator():
    yield "A"
    yield "B"
    yield "C"

gen = simple_generator()
print(next(gen))  # A
print(next(gen))  # B
print(next(gen))  # C
print(next(gen))  # StopIteration 例外が発生
  • yield によって “A” → “B” → “C” の順で値が返る。
  • すべての yield を通過すると、StopIteration 例外が発生。

forループでジェネレーターを処理する

for ループを使うと、自動的にジェネレーターの next() を呼び出して処理できます。

# forループでジェネレーターを処理
def count_down(n):
    while n > 0:
        yield n
        n -= 1

for num in count_down(5):
    print(num)  # 5 4 3 2 1
  • for ループが自動的に next() を呼び出し、値を取得。
  • ループ終了時に StopIteration が発生しても自動的に処理が終了。

yield を使った無限ループ

yield を使うと、メモリ効率の良い無限ループを作成できます。

# 無限ループのジェネレーター
def infinite_counter():
    n = 0
    while True:
        yield n
        n += 1

counter = infinite_counter()
print(next(counter))  # 0
print(next(counter))  # 1
print(next(counter))  # 2
  • while True を使って、無限に値を生成。
  • next() を呼び出すたびに次の値が得られる。

yield を使って値を受け取る

ジェネレーターに外部から値を送ることも可能です。

# send() でジェネレーターに値を送る
def echo():
    while True:
        received = yield
        print(f"受信: {received}")

gen = echo()
next(gen)  # ジェネレーターを開始
gen.send("Hello")  # 受信: Hello
gen.send("Python")  # 受信: Python
  • yield の左辺に変数を指定すると、send() で値を送信可能。
  • next(gen) を最初に呼び出してジェネレーターを開始する必要がある。

yield の注意点

  • ジェネレーターは 1 度しかイテレーションできない: もう一度ループを回すには、新しくジェネレーターを作る必要がある。
  • メモリ効率が良い: リストを返す関数よりも、大量のデータを扱う際に有利。
  • デバッグが難しい: 状態を保持するため、途中の処理が把握しづらいことがある。

yield のよくある質問

Q: yield と return の違いは?
A: return は関数を完全に終了し、yield は状態を保持したまま一時停止する。
Q: yield のメリットは?
A: 大量のデータを一度に処理せず、必要な分だけ遅延評価できるため、メモリ消費を抑えられる。
Q: ジェネレーターをリストのように扱えますか?
A: list(generator) を使えば、すべての要素をリストに変換できるが、メモリ効率の良さが失われる。

まとめ

yield は、ジェネレーターを作成し、データを一時停止しながら処理できる強力なキーワードです。

  • 関数の状態を保持しつつ、データを順次生成できる。
  • 大規模データを効率的に処理するのに適している。
  • send() を使えば、外部からデータを注入可能。

適切に yield を活用し、効率的なデータ処理を実現しましょう。