Pythonのジェネレータ関数とジェネレータの基本について解説します。
ジェネレータ関数とジェネレータ
Pythonにおけるジェネレータ関数とは、yield
文を使って値を返却する関数であり、その実行によってジェネレータというオブジェクトが作成されます。ジェネレータはイテレータの一種であり、逐次的に値を生成して返すオブジェクトのことを言います。なお、イテレータについては「イテレータの基本」を参考にしてください。
このため、ジェネレータを使うとシーケンス全体をメモリ上に展開せず、無限のシーケンスであっても必要な時に必要な値だけを生成することができ、メモリ使用量を大幅に削減できます。
この記事では、ジェネレータ関数とジェネレータについて基本の使い方を紹介します。
ジェネレータ関数の定義方法
ジェネレータ関数は、通常の関数とほぼ同じ定義方法ですが、return
文の代わりにyield
文を使用します。
# ジェネレータ関数 def generate_char(): yield "A" yield "B" yield "C" if __name__ == "__main__": gen = generate_char() print(type(gen)) # Aが出力される print(next(gen)) # Bが出力される print(next(gen)) # Cが出力される print(next(gen))
【実行結果】 <class 'generator'> A B C
上記のgenerate_char
関数は、"A"
、"B"
、"C"
という文字列を順に返すジェネレータ関数です。gen
はジェネレータのオブジェクト(<class 'generator'>
)となります。
ジェネレータはイテレータの一種であり、__next__()
メソッドが実装されているため、next
関数を使って順番に値を取り出せます。
ジェネレータ関数はyield
文まで実行され、その位置を記憶します。次に呼び出されると、その位置から実行を再開します。例えば、最初の呼び出しではyield "A"
が実行され、次の呼び出しではyield "B"
が実行されます。
yield "C"
までが実行され、さらに次の呼び出しで返す値がなくなると、ジェネレータは、StopIteration
例外を送出します。
ジェネレータはイテレータの一種のためfor
文で使用できます。
# ジェネレータ関数 def generate_char(): yield "A" yield "B" yield "C" if __name__ == "__main__": # for文でのジェネレータ関数の使用 for s in generate_char(): print(s)
【実行結果】 A B C
上記結果のようにジェネレータが生成する値("A"
、"B"
、"C"
)を順に取り出せていることが分かります。
range
をジェネレータ関数で実現する
Pythonのfor
文では、数値シーケンスの生成にrange
をよく使用します。range
はジェネレータ関数として実現されています。
ジェネレータ関数の使用方法を覚えるためにrange
と同じ動作をするジェネレータ関数を作ってみましょう。
# ジェネレータ関数でrangeと同じ動作を実現 def sample_range(start=0, stop=10, step=1): num = start while num < stop: yield num num += step if __name__ == "__main__": iter_range = sample_range(0, 5) print(type(iter_range)) print(next(iter_range)) print(next(iter_range)) print(next(iter_range)) print("======================") for i in iter_range: print(i)
【実行結果】 <class 'generator'> 0 1 2 ====================== 3 4
上記のsample_range
関数は、range
と同じ動作をするジェネレータ関数です。iter_range
は、ジェネレータのオブジェクト(<class 'generator'>
)となっています。
そのため、next
で値を順に取り出せていることが分かります。また、途中で「"==="
」のようなprint
の中断を入れていますが、次の呼び出しでは後続の値から取り出しができていることが分かります。
ジェネレータ関数を使用することで、一度にメモリ上に展開できないような無限に続くような数列なども実現可能になります。
ジェネレータ内包表記
ジェネレータは、ジェネレータ内包表記というシンプルな記載方法でも生成することができます。ジェネレータ内包表記については「ジェネレータ内包表記の使い方」を参考にしてください。
まとめ
Pythonのジェネレータ関数とジェネレータの基本について解説しました。
ジェネレータ関数は、yield
文を使って値を返却する関数であり、ジェネレータオブジェクトを作成します。ジェネレータはイテレータの一種なので逐次的に値を生成することができます。この記事では、ジェネレータ関数の定義方法の例とジェネレータの使用例を紹介しました。
ジェネレータは一度にメモリ上に展開できないような無限に続くシーケンスを扱うこともできて便利です。ぜひ、使い方を覚えてもらいたいと思います。
上記で紹介しているソースコードはgithubにて公開しています。参考にしていただければと思います。