🫥
Pythonのyieldの動きと使い方について
はじめに
pythonコードを書いている時に、yieldの動きと使い所について調べたので本記事でまとめます。
yieldとは?
-
returnと似ているが、ジェネレーターと呼ばれる特殊なイテレータが生成される- イテレータとは、リストなどデータを一つずつ順番に取り出すオブジェクト
- リストはメモリ上に全ての要素を保持する一方で、ジェネレーターは必要に応じて値を一つずつ保持する
-
yieldを含む関数を「ジェネレーター関数」とも呼ぶ
-
yieldが実行されるたびに関数は一時停止、再度関数を呼び出すと続きから実行する
以下にコード例を示します。
# ジェネレーター関数を定義
def generate_numbers():
for i in range(1,4):
yield i
# 関数を呼び出すだけでは、ジェネレーターオブジェクトが生成されるのみ
numbers = generate_numbers()
print(numbers) # <generator object generate_numbers at 0x00000000e0>
# next()を使い、値を一つずつ取得することもできる
print(next(numbers)) # 1
print(next(numbers)) # 2
何が嬉しいのか?
上記だけ見ると「returnやlistで同じようなことができるじゃん」という感じですが、
yieldの良さももちろんあります。
それは、 「リストに比べると少ないメモリ量で処理を実行することができる」 点です。
前述した通り、リストの場合は全データを保持するメモリ領域を確保する挙動になります。例えば100万個の要素が入っているリストを宣言した場合、100万個分の要素が入るメモリ領域を確保します。
一方で、yieldは今の関数の状態だけメモリに保持し、必要な時に要素を取得するためメモリが小さくて済みます。
若干脱線:pytestにおけるyield
個人的にはpythonのテストフレームワークの一つであるpytestでyieldをよく見かけます。
test関数を実行する前のsetup関数内で、テスト実行前の処理とテスト実行後の処理の間にyieldを入れることで、テスト実行前の処理を実行 -> yield -> テスト実行後の処理を実行
Discussion