Python | ジェネレータ関数の使い方
公開日:2021/5/26
Pythonでは,ジェネレータ関数を用いるとメモリの使用量を減らすことができる.そのため,非常に大きなデータを操作しなければならないとき,ジェネレータ関数が有用になる.ただし,処理が遅くなる欠点もある.ジェネレータ関数は,ユーザー定義関数のように定義をし,yieldが用いられる特徴がある.以下にジェネレータ関数を用いた構文を記載する.
◆実施環境
Python 3.8.8
■for文を用いたジェネレータ関数の作成1
ジェネレーター関数を作成するには,通常のユーザー定義関数と同じように,defの後ろに関数名を定義する.関数名の後ろには”():”を加え,次行インデントした上で,yieldを記載する.yieldの後ろの値は要求の度に返される.
def ジェネレータ関数():
yield x
以下では2行目に”generator”という名のジェネレータ関数を作成し,3行目でprint関数の処理を実装した.5行目にyieldを記載した.n = next(gen)でジェネレーター関数を呼び出し,yieldの変数が返る.print(n)で出力される.
# 1の処理
def generator(i):
print('Good morning')
for n in range(i):
yield f'Good afternoon:{n}' # nの回数が変化
gen = generator(3)
n = next(gen) # ジェネレーター関数を呼びだし,"Good morning"が出力
print(n) # "Good afternoon:0"が出力
n = next(gen)
print(n) # "Good afternoon:1"が出力
n = next(gen)
print(n) # "Good afternoon:2"が出力
n = next(gen) # "エラー(StopIteration)"が出力
■実行結果
# 1の結果
Good morning
Good afternoon:0
Good afternoon:1
Good afternoon:2
StopIteration # エラー出力
■for文を用いたジェネレータ関数の作成2
# 1の処理
def generator(i):
print('Good morning')
for n in range(i):
yield f'Good afternoon:{n}'
gen = generator(5)
for x in gen:
print(x)
■実行結果
# 1の結果Good morning
Good afternoon:0
Good afternoon:1
Good afternoon:2
Good afternoon:3
Good afternoon:4
■while文を用いたジェネレータ関数の作成
# 1の処理
def generator(i):
print('Good morning')
n = 0
while n < i:
yield f'Good afternoon:{n}'
n += 1
gen = generator(6)
for x in gen:
print(x)
■実行結果
# 1の結果
Good morning
Good afternoon:0
Good afternoon:1
Good afternoon:2
Good afternoon:3
Good afternoon:4
Good afternoon:5
■ジェネレータ関数でのsendの利用
sendを利用してyieldに値を送ることができる
# 1の処理
def generator(i):
print('Good morning')
for n in range(i):
x = yield n
print(x)
print('Good evening')
gen = generator(10)
next(gen) # "Good morning"が出力
next(gen) # None, "Good evening"が出力
gen.send(8) # 8がxに送られ,8と"Good evening"が出力
■実行結果
# 1の結果
Good morning
None
Good evening
8
Good evening
■ジェネレータ関数でのthrowの利用
throwを利用してエラーを意図的に発生させることができる.なお,#1の処理では通常のエラー(NameError)を出力し,#2の処理ではtry~excepを利用した例外処理を実装した.
# 1の処理(エラー発生)
def generator(i):
print('Good morning')
for n in range(i):
x = yield n
print(x)
print('Good evening')
gen = generator(10)
next(gen)
gen.throw(NameError('名前が見つからない'))
# 2の処理(try~exceptで例外処理)
def generator(i):
print('Good morning')
for n in range(i):
try:
x = yield n
print(x)
print('Good evening')
except NameError as e:
print(e, type(e))
gen = generator(10)
next(gen)
gen.throw(NameError('名前が見つからない'))
■実行結果
# 1の結果
Good morning
Traceback (most recent call last): # 以降のエラーは途中省略
NameError: 名前が見つからない # エラーの最後の文
# 2の結果
Good morning
名前が見つからない <class 'NameError'>
■ジェネレータ関数でのcloseの利用
closeを利用してジェネレータ関数を終了させることができる.
# 1の処理
def generator(i):
print('Good morning')
for n in range(i):
x = yield n
print(x)
print('Good evening')
gen = generator(10)
next(gen)
gen.close() # 処理を終了させる
next(gen) # エラーが発生する
■実行結果
# 1の結果
Good morning
StopIteration
以上