Pythonの「yield」キーワードとは?ジェネレータの仕組みと使い方を徹底解説
Pythonのyieldキーワードは、ジェネレータ(generator)を作成するために使用されます。その動作を理解するには、まず「イテラブル(iterable)」と「イテレータ(iterator)」について知っておく必要があります。
イテラブルとイテレータとは
リスト、文字列、ファイルなどのPythonオブジェクトは「イテラブル」と呼ばれます。for ... in構文で走査(反復処理)できるオブジェクトが、すべてイテラブルです。
イテレータオブジェクトもイテラブルの一種ですが、一度しか反復処理できないという特徴があります。任意のイテラブルからはiter()関数を使ってイテレータを取得でき、イテレータはnext()メソッドを持っており、これによって反復処理を行います。
以下のコードは、リストからイテレータを作成し、next()メソッドで要素を順に取り出す例です。
>>> L1 = [1,2,3,4]
>>> I1 = iter(L1)
>>> while True:
try:
print (next(I1))
except StopIteration:
sys.exit()
ジェネレータとyieldの動作
ジェネレータは関数によく似た外見を持っていますが、yieldキーワードによってイテレータの要素を順次返す点が異なります。
ジェネレータ関数を呼び出しても、関数本体の実行は開始されず、イテレータオブジェクトが返されるだけです。最初にnext()メソッドが呼び出された時点で、関数の実行が開始され、yieldステートメントに到達するとそこで値を返します。
ここが重要なポイントですが、yieldは最後の実行状態を記憶しています。つまり、2回目のnext()呼び出しでは、前回中断した位置から処理が再開されるのです。この仕組みにより、大量のデータでもメモリ効率よく逐次処理できます。
実例:フィボナッチ数列を生成するジェネレータ
次の例では、フィボナッチ数列を含むイテレータを生成するジェネレータ関数を定義しています。ジェネレータ関数fibo()への各呼び出し(next()による実行)は、フィボナッチ数列の次の要素を順に返します。
import sys
def fibo(n):
a,b=0,1
while True:
if a>n : return
yield a
a, b = b, a+b
f = fibo(20)
while True:
try:
print (next(f))
except StopIteration:
sys.exit()
このコードでは、20以下のフィボナッチ数(0, 1, 1, 2, 3, 5, 8, 13)が順番に出力されます。a > nとなった時点でreturnが実行され、それ以降のnext()呼び出しではStopIteration例外が発生してループが終了します。
まとめ
yieldはジェネレータ関数内で使用され、値を返しつつ関数の実行状態を保持する- ジェネレータ関数を呼び出しても即座には実行されず、イテレータオブジェクトが返る
next()を呼ぶたびに、前回yieldした位置から処理が再開される- 全データを一括で保持せずに済むため、メモリ効率の良い処理が可能
-
【初心者向け】Pythonの if __name__ == "__main__" の意味と使い方を徹底解説
Pythonインタープリターがソースファイルを読み込むと、そのファイル内に書かれたすべてのコードが実行されます。特殊変数 __name__ の正体コードを実行する前に、Pythonはいくつかの特殊な変数を定義します。その一つが __name__ です。Pythonインタープリターがそのモジュール(ソースファイル)をメインプログラムとして直接実行している場合、__name__ には __main__ という値が設定されます。逆に、そのファイルが別のモジュールからインポートされた場合には、__name__ にはモジュール名が設定されます。なぜこのチェックが必要なのか?この仕組みが役立つ理由は、開発
-
Pythonのreload()関数とは?モジュールを再読み込みする方法を解説
Pythonのreload()関数とはPythonのreload(moduleName)関数は、すでに読み込まれているモジュールを再読み込み(リロード)するための機能です。モジュールを読み込む際は、通常どおり import moduleName の構文でインポートしておく必要があります。この関数は、対話型セッションでの利用を想定して設計されています。たとえば、モジュールのソースファイルを編集した後、Pythonインタプリタを終了して再起動することなく、変更内容をすぐにテストしたい場合に便利です。reload()の基本的な使い方以下は、モジュールを編集した後に再読み込みする基本的な例です。>