ジェネレータ
ジェネレータはプログラムの進行に応じて値を計算して返すことのできるオブジェクトであり、イテレータの一種である。
1. yield文で値を返すよう定義された関数はジェネレータ関数となる。
2. ジェネレータ関数を呼び出すことによりジェネレータ型インスタンスが生成される。
3. ジェネレータ__next__メソッドを呼び出す度に値を呼び出し元に返す。この動作はreturn文に似ている。
4. 返す要素が無くなったならば、例外を返す。
まずは通常の関数の動作を確認しよう。
code:generator00.py
def func1():
return 'First message'
return 'Second message'
return 'Third message'
print(type(func1))
print(func1())
print(func1())
print(func1())
関数func1において、先頭のreturn文が実行された時点で、関数func1の処理は終了し、スタックに積まれた関数func1の処理はメモリから消えてなくなる。
関数func1は呼出しの度に新たな処理が生成され、スタックに積まれる。
return文ではなく、yield文で値を返すジェネレータ関数func2を作ってみよう。
func2の呼出しによってジェネレータが生成される。ジェネレータはイテレータの一種であり、__next__メンバを有する。
code:generator02.py
def func2():
yield 'First message'
yield 'Second message'
yield 'Third message'
gen2 = func2() # ここでジェネレータ・インスタンス(オブジェクトが生成される)
print(type(gen2))
print(gen2.__next__()) # 最初の呼出し
print(gen2.__next__()) # 次の呼出し
print(gen2.__next__())
# print(gen2.__next__()) 例外 StopIteration を吐いて停止する
1. ジェネレータは、最初の__next__メソッドが呼び出されると処理が先頭から開始され、yieldで値を返した後も内部状態を保持したままメモリ上に残り続ける。
2. 次の__next__メソッド呼出しが行われると、前回呼出しの最後に実行したyield文の直後から処理が再開される。
3. yield文で帰す値が無くなると、例外を返す。
next関数【builtin】を使って__next__メソッドを呼び出すことができる。
code:generator03.py
def func3():
yield 'First message'
yield 'Second message'
yield 'Third message'
gen3 = func3()
print(next(gen3))
print(next(gen3))
print(next(gen3))
無限長のイテレータを作ることができる。長大な時系列データのタイムスタンプ生成などを目的とする場合はメモリを節約することができる。
code:generator04.py
def func4():
i = 0
while True:
yield i
i += 1
gen4 = func4()
for i in range(100000):
print(next(gen4), end=' / ')
関連:イテラブル、イテレータ
まとめ
通常の関数:
関数呼び出しを行うと、return文て指定した値が返される。
ジェネレータ関数
関数呼び出しを行うと、ジェネレータ型のインスタンスが返される。
ジェネレータの__next__メソッドを呼び出すと、yield文で指定した値が返される。