python3.doc_11
R e i - D r e a m
for Laravel
TOP > Python3 > Python基本(ジェネレータ)
Guest
login

最終投稿日:2022年6月18日

Python基本(ジェネレータ)
ジェネレータとは
通常の関数は呼び出すと return で値を1回返却して処理を終了します。
しかし、ジェネレータは処理の途中で複数回値を返却する様な振る舞いをします。
例)
def gen_123():            ※定義は通常の関数と同じ
yield 1                      ※return に対して yield (シールドと読む)で値を返却する
yield 2                      ※yield は複数個記述できる
yield 3
g = 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文ならインスタンスにしなくても大丈夫。。
サブジェネレータ
ジェネレータは内部でジェネレータをを扱うことが可能です。
例)
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 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
途中で値を受け取るジェネレータ
yield とは実は式で、send メソッドを使うと直前に yield した部分に値を送り込むことができる。
例)
    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 += 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」と表示される
● try ~ except 文を使うと
try:
    ret = gen_ret()
    print( next( ret ) )
    print( next( ret ) )
    print( next( ret ) )
except StopIteration as e:
    print( e.args )                      ※キャッチされると ( 'hoge', ) とマルチプル型で出力される
サブジェネレータの返却する値を受け取る
前述した[yield from]を使ったサブジェネレータでは、サブジェネレータ内のイテレータが終了すると次の処理に実行しています。
この、イテレータの終了時に 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 と表示される
ログインしてコメントを残そう!!


きっぷる