最終投稿日:2022年6月18日
Python基本(ジェネレータ)
ジェネレータとは
通常の関数は呼び出すと return で値を1回返却して処理を終了します。
しかし、ジェネレータは処理の途中で複数回値を返却する様な振る舞いをします。
しかし、ジェネレータは処理の途中で複数回値を返却する様な振る舞いをします。
例)
def gen_123(): ※定義は通常の関数と同じ
print( next( g ) ) ※ 1を返却する
print( next( g ) ) ※ 2を返却する
print( next( g ) ) ※ 3を返却する
print( next( gen_123() ) ) ※ 1を返却する
※インスタンスにしないと内部的に順番を記憶できない
print( next( gen_123() ) ) ※ 1を返却する
print( next( g ) ) ※ エラーとなる
※yield の個数以上の呼び出しを行うとエラーとなる(ポインタは戻せません!) g = gen_123()
for i in g: print(i) ※ 1 2 3 と取得できる for i in gen_123():
print(i) ※ 1 2 3 と取得できる
※for文ならインスタンスにしなくても大丈夫。。
yield 1 ※return に対して yield (シールドと読む)で値を返却する
yield 2 ※yield は複数個記述できる
yield 3
g = gen_123() ※変数に代入するには、関数と違いカッコが必要です!yield 2 ※yield は複数個記述できる
yield 3
print( next( g ) ) ※ 1を返却する
print( next( g ) ) ※ 2を返却する
print( next( g ) ) ※ 3を返却する
print( next( gen_123() ) ) ※ 1を返却する
※インスタンスにしないと内部的に順番を記憶できない
print( next( gen_123() ) ) ※ 1を返却する
print( next( g ) ) ※ エラーとなる
※yield の個数以上の呼び出しを行うとエラーとなる(ポインタは戻せません!) g = gen_123()
for i in g: print(i) ※ 1 2 3 と取得できる for i in gen_123():
print(i) ※ 1 2 3 と取得できる
※for文ならインスタンスにしなくても大丈夫。。
サブジェネレータ
ジェネレータは内部でジェネレータをを扱うことが可能です。
例)
def gen_123():
yield 1
yield 2
yield 3 def gen_abc():
yield 'a'
yield 'b'
yield 'c' def gen_multi():
g1 = gen_123()
g2 = gen_abc()
for i in g1:
yield i for i in g2:
yield i for i in gen_multi():
print( i ) ※123abc と表示される
yield 1
yield 2
yield 3 def gen_abc():
yield 'a'
yield 'b'
yield 'c' def gen_multi():
g1 = gen_123()
g2 = gen_abc()
for i in g1:
yield i for i in g2:
yield i for i in gen_multi():
print( i ) ※123abc と表示される
● [yield from]を利用する
前述の以下の部分は、[yield from]に置き換える事ができます。
for i in g1:
yield i
ジェネレーター[gen_multi()]を以下の様にしても結果は同じとなります。
def gen_multi():
g1 = gen_123()
g2 = gen_abc()
yield from g1
yield from g2
for i in g1:
yield i
ジェネレーター[gen_multi()]を以下の様にしても結果は同じとなります。
def gen_multi():
g1 = gen_123()
g2 = gen_abc()
yield from g1
yield from g2
途中で値を受け取るジェネレータ
yield とは実は式で、send メソッドを使うと直前に yield した部分に値を送り込むことができる。
例)
前述の式[v += yield v]は特殊な式です。[v = v + yield v]とは書けないので注意!
def accum():
v = 0 ※初期値
while True: ※send で渡された回数だけループ
v += yield v a = accum()
print( next( a ) ) ※next で初期化する
※初期値の 0 が返却される
print( a.send( 1 ) ) ※1回ループされる
※ 0 + 1 で 1 が返却される
print( a.send( 1 ) ) ※1回ループされる
※現在のインスタンスの値 1 + 1 で 2 が返却される
print( a.send( 2 ) ) ※2回ループされる
※現在のインスタンスの値 2 + 1 + 1 で 4 が返却される
【メモ】v = 0 ※初期値
while True: ※send で渡された回数だけループ
v += yield v a = accum()
print( next( a ) ) ※next で初期化する
※初期値の 0 が返却される
print( a.send( 1 ) ) ※1回ループされる
※ 0 + 1 で 1 が返却される
print( a.send( 1 ) ) ※1回ループされる
※現在のインスタンスの値 1 + 1 で 2 が返却される
print( a.send( 2 ) ) ※2回ループされる
※現在のインスタンスの値 2 + 1 + 1 で 4 が返却される
前述の式[v += yield v]は特殊な式です。[v = v + yield v]とは書けないので注意!
ジェネレータの戻り値
実はジェネレータにも return が使えます。
○ 小項目文字列
例)
def gen_ret():
yield 1
yield 2
return 'hoge' for i in gen_ret():
print( i ) ※結果は 1 2 と返却され、return 部分は返却されない ret = gen_ret()
print( next( ret ) ) ※結果は 1 が返却される
print( next( ret ) ) ※結果は 2 が返却される
print( next( ret ) ) ※エラーとなり、エラー文言に「StopIteration: hoge」と表示される
yield 1
yield 2
return 'hoge' for i in gen_ret():
print( i ) ※結果は 1 2 と返却され、return 部分は返却されない ret = gen_ret()
print( next( ret ) ) ※結果は 1 が返却される
print( next( ret ) ) ※結果は 2 が返却される
print( next( ret ) ) ※エラーとなり、エラー文言に「StopIteration: hoge」と表示される
● try ~ except 文を使うと
try:
ret = gen_ret()
print( next( ret ) )
print( next( ret ) )
print( next( ret ) )
except StopIteration as e:
print( e.args ) ※キャッチされると ( 'hoge', ) とマルチプル型で出力される
ret = gen_ret()
print( next( ret ) )
print( next( ret ) )
print( next( ret ) )
except StopIteration as e:
print( e.args ) ※キャッチされると ( 'hoge', ) とマルチプル型で出力される
サブジェネレータの返却する値を受け取る
前述した[yield from]を使ったサブジェネレータでは、サブジェネレータ内のイテレータが終了すると次の処理に実行しています。
この、イテレータの終了時に return の値を取得する事ができます。
例)
この、イテレータの終了時に return の値を取得する事ができます。
例)
def gen_123():
yield 1
yield 2
yield 3
return 'hoge' def gen_abc():
yield 'a'
yield 'b'
yield 'c'
return 'foo' def gen_multi():
g1 = gen_123()
g2 = gen_abc()
r1 = yield from g1 ※終了時に r1 に hoge が代入される
r2 = yield from g2 ※終了時に r1 に foo が代入される
yield r1
yield r2 for i in gen_multi():
print( i ) ※1 2 3 a b c hoge foo と表示される
yield 1
yield 2
yield 3
return 'hoge' def gen_abc():
yield 'a'
yield 'b'
yield 'c'
return 'foo' def gen_multi():
g1 = gen_123()
g2 = gen_abc()
r1 = yield from g1 ※終了時に r1 に hoge が代入される
r2 = yield from g2 ※終了時に r1 に foo が代入される
yield r1
yield r2 for i in gen_multi():
print( i ) ※1 2 3 a b c hoge foo と表示される




