関数とyield文によるジェネレーター
イテレータが__next__
メソッドでコレクションの要素を取り出すのに有用なのに対して、ジェネレーターはyield
文で任意の結果を順次返していく。関数内にyield文を書くと、その関数はジェネレーターになる。
1 2 3 4 5 6 7 8 9 10 |
def generator(): yield 1 yield 'A' yield 2 yield 'B' gen = generator() for n in gen: print(n, end=' ') # 1 A 2 B |
ジェネレーターは以下のように構成する。
- ジェネレーターは関数として定義され、その関数への参照として取得する
- forブロックのループのたびにジェネレーターの中の
yield
が順次1つずつ呼び出される - 呼び出せる
yield
文がなくなるか、forブロックで強制的に抜け出したときループが終了
先の例ではjoin
文が4回だけ呼び出されるので、それが呼べなくなったときにループが終了する。これに対して次の例では、ジェネレーターは無限に結果を生成し続け、forブロックで条件に合致したときにループを終了させている。
1 2 3 4 5 6 7 8 9 10 11 12 |
def generator(): a = 1 while True: yield a a += 1 gen = generator() for n in gen: print(n, end=' ') if n == 10: break # 1 2 3 4 5 6 7 8 9 10 |
ジェネレーター式
内包表現と同じ表現を()内に書くと、要素を一つずつ生成するジェネレーターオブジェクトを返す。
1 2 3 4 5 |
gen = (x*x for x in range(5)) for x in gen: print(x, end=' ') # 0 1 4 9 16 |