これはなに
Pythonのジェネレータとは何かを調べたメモ。
ジェネレータとは
Pythonにおけるジェネレータとは、遅延評価の性質を持つ特別なイテレータの一種である。
ジェネレータはイテレータであるため、__iter__()
と__next__()
の2つのメソッドを持つ。また、遅延評価の性質を持つため、__next__()
メソッドが呼ばれるまで次の要素を生成しない。__next__()
メソッドが呼ばれてはじめて次の要素を生成する。
ジェネレータの定義方法
ジェネレータの作成方法は下記の2つがある。
- ジェネレータ式の利用
- ジェネレータ関数の利用
ジェネレータ式とは
ジェネレータ式はジェネレータを返す記法である。 基本的な形は以下のようになる。リスト内法表記と似ている。
generator = (expression for item in iterable)
たとえば、下記コードは与えられたリストの各要素を2乗するジェネレータである。
numbers = [1, 2, 3, 4, 5]
squared = (x * x for x in numbers)
for number in squared:
print(number) # 1 4 9 16 25
ジェネレータ式に条件を設けることもできる。たとえば、上記のリストから偶数だけを取り出して2乗するジェネレータは次のようになる。
even_squared = (x * x for x in numbers if x % 2 == 0)
for number in even_squared:
print(number) # 4 16
ジェネレータ関数とは
ジェネレータ関数とは、ジェネレータを生成する関数である。通常の関数と同様にdef
で定義するが、return
の代わりにyield
を使用する。yield
を使用すると、関数はジェネレータイテレータを返す。
基本的なジェネレータ関数の例を以下に示す。これは、0からlimit
に指定した数までの整数を順に返す。
def count_up_to(limit):
count = 0
while count <= limit:
yield count
count += 1
counter = count_up_to(5)
for number in counter:
print(number) # 1 2 3 4 5
ジェネレータ関数は実行状態を保持する。そのため、次回の呼び出し時には前回の状態から続けて実行できる。また、ジェネレータ関数はジェネレータを返すため、要素を必要とするタイミングでのみ評価される。
ジェネレータの利点
ジェネレータは__next__()
メソッドが呼ばれるまで次の要素を生成しないため、メモリ効率が良い。また、一度にすべてのデータをメモリに保持する必要がないため、大量のデータを扱う際にも役立つ。
ジェネレータの利用シーン
- 大規模なデータセット
- 無限長のシーケンス
- 計算量の大きいシーケンス
ジェネレータの注意点
- 一度
next()
で呼び出した値は破棄される。そのため、一度イテレートした後に再度イテレートする場合は、新たにジェネレータインスタンスを生成しなければならない - ジェネレータ関数は
yield
文を実行した時点で一時停止する。そのため、次の呼び出しあるいは関数の終了まで関数の実行は保持される