Categories: Python

【Python】ジェネレータの定義と使い方を解説

この記事では、Pythonのジェネレータの使い方を解説します。

ジェネレータとは、イテレータを簡単に作成するための機能です。リストやタプルなどを使わなくても複数の値を返す関数を定義することができます。

イテレータについては、以下の記事を参考にしてください。

Linkイテラブルとイテレータについて

それでは、ジェネレータの使い方を見ていきましょう!

ジェネレータ関数の定義

ジェネレータ関数は、関数内でyield文を使って値を返します。

def 関数名(): yield 戻り値

yieldは、同時にいくつでも定義することもできます。

def 関数名(): yield 戻り値1 yield 戻り値2 yield 戻り値3
  • yield文が処理されても関数は終了しない

例として、簡単なジェネレータ関数を定義して呼び出してみる。その際、生成したジェネレータとオブジェクトの型を出力する。 :

# ジェネレータ関数 def func(): yield 1 yield 'Hello' yield [1, 2, 3] result = func() print(result, type(result)) # <generator object func at 0x10e904a00> <class 'generator'>

このように、ジェネレータ関数は値をジェネレータオブジェクトとして返します。

ジェネレータオブジェクト

ジェネレータ関数を実行すると、以下のような「ジェネレータオブジェクト(ジェネレータイテレータ)」が返されます。

<generator object 関数名 at 0x10bef73d0>

ジェネレータオブジェクトは、for文で各要素にアクセスしたり、

for val in ジェネレータオブジェクト: print(val)

リストやタプルに変換することができます。

list(ジェネレータオブジェクト)

例として、渡された文字列を1文字ずつ文字コードにして返すジェネレータ関数から生成したジェネレータオブジェクトをfor文で実行してみたり、リストに変換してみる :

def ords(string: str): for char in string: # yieldで文字コードを返す yield ord(char) for o in ords('abc'): print(o) # リストに変換 print(list(ords('abc')))

実行結果

97 98 99 [97, 98, 99]

ジェネレータの仕組み

ジェネレータは、以下のように処理されています。

  1. yield文で値を返した時に処理を中断し、その場所を記憶する
  2. 新たに値が要求されたら記憶した場所から処理を再開する

これを繰り返すことでジェネレータは複数の値を返しています。値が要求されるたびに演算して要素を返すため処理や使用するメモリを分散することができ、効率が良いとされています。

例えば以下のコードを見てください。next()で要素を要求されるたび、関数内のprint()によって値が出力されているのがわかります。

def generator(): print('start') print('yield 1') yield 1 print('yield 2') yield 2 print('yield 3') yield 3 print('end') g = generator() # next()で次の要素を要求できる print('next 1') print(next(g)) print('next 2') print(next(g)) print('next 3') print(next(g)) print('next 4') print(next(g))

実行結果

next 1 start yield 1 1 next 2 yield 2 2 next 3 yield 3 3 next 4 end Traceback (most recent call last): File "main.py", line 22, in <module> print(next(g)) StopIteration

このように、ジェネレータは値を要求されるたびに演算して要素を返しています。処理が膨大な場合にはジェネレータを使うことでコストを分散させることができます。

ジェネレータオブジェクトは使い回せない

ジェネレータオブジェクトが呼び出された場合、記憶した場所から処理を再開します。例えば、以下のような場合も同様です。

def func(): yield 1 yield 2 yield 3 g = func() print('1度目のループ') for v in g: print(v) print('2度目のループ') for v in g: print(v)

実行結果

1度目のループ 1 2 3 2度目のループ

1度目のループで最後の要素まで処理したので、2度目のループでは何も出力されません。何度も参照したい場合は、リストやタプルに変換して使いましょう!

ジェネレータ式

単純なジェネレータならば、さらに簡潔に式として記述することができます。ジェネレータ式は、内包表記と同じ書き方をします。[]ではなく()を使う点に注意してください

(戻り値 for 変数名 in イテラブルオブジェクト)

例として先ほどのサンプルで作成したジェネレータ関数をジェネレータ式で書き換えてみます :

元のコード

def ords(string: str): for char in string: # yieldで文字コードを返す yield ord(char) for o in ords('abc'): print(o)

ジェネレータ式で書き換えたコード

for n in (ord(char) for char in 'abc'): print(n)

実行結果

97 98 99

for文と合わせて2行で実装できてしまいました。このように単純なジェネレータはジェネレータ式を使うことで簡単に実装できます。

まとめ

この記事では、Pythonのジェネレータの使い方を解説しました。

ジェネレータを使う機会は多くないですが、複数の値を返したいけどリストやタプルなどを使いたくない場合は実装を検討してみてはいかがでしょうか?

一度で処理するにはコストがかかり過ぎる場合にもジェネレータを使うことを考慮しましょう!

今回のおさらい

簡単に今回のコードをおさらいしておきましょう!

# ジェネレータ def 関数名(): yield 戻り値1 yield 戻り値2 yield 戻り値3 # ジェネレータ式 (戻り値 for 変数名 in イテラブルオブジェクト)

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ

ゆうまる

独学でプログラミングを勉強しているおじさん。いろんな言語を勉強したが浅く広くなためあまり仕事につながらない。また忘れっぽいため自分のブログを備忘録としても使っている。産まれてこのかたずっとネコを飼ってる生粋のネコ派。最近お腹が出てきて筋トレに奮闘中!

View Comments

    Recent Posts

    リッチなソースコードをブログに載っける方法

    この記事では、ブログにソースコードを記述…

    2か月 ago

    【Mac】Homebrew自体のアンインストール

    この記事では、パッケージ管理システムであ…

    2か月 ago

    【Python】MeCab(めかぶ)を使って形態素解析する

    この記事では、Pythonで「MeCab…

    2か月 ago

    【Python】pytubeを使ってYouTubeの動画をダウンロードする

    この記事ではpytubeを使ってYouT…

    2か月 ago

    【Python】Icrawlerを使って画像を大量にダウンロードする

    この記事では、Icrawlerを使って画…

    2か月 ago

    【Python】Seleniumを使ってWebブラウザを自動化する

    この記事では、Seleniumを使ってW…

    2か月 ago