キコーナ 伊勢 佐 木k8 カジノ[Python入門]ジェネレータ関数とジェネレータイテレータの基礎仮想通貨カジノパチンコ楽園 大宮 新台

キコーナ 伊勢 佐 木k8 カジノ[Python入門]ジェネレータ関数とジェネレータイテレータの基礎仮想通貨カジノパチンコ楽園 大宮 新台

キコーナ 伊勢 佐 木k8 カジノ[Python入門]ジェネレータ関数とジェネレータイテレータの基礎仮想通貨カジノパチンコ楽園 大宮 新台

カスタム 出版 と はk8 カジノ 「Python入門」のインデックス

化 物語 スロット いつまで連載目次

 前回はPythonのイテレータについて見た後に、自分でイテレータを定義した。今回はイテレータを戻り値とするジェネレータ関数と呼ばれる機構について見ていこう。

今回の目次ジェネレータ関数とジェネレータイテレータ簡単なジェネレータ関数の定義カウントアップするジェネレータイテレータyield式の値とsendメソッドジェネレータ関数とジェネレータイテレータ

 ジェネレータ(ジェネレータ関数)とは、イテレータを作成するための関数のことだ。ジェネレータによって作成されたイテレータのことを特に「ジェネレータイテレータ」と呼ぶこともある。またはジェネレータ関数で作成されたイテレータのことを単純に「ジェネレータ」と呼ぶこともある。本稿では、イテレータを戻り値とする関数のことを「ジェネレータ関数」と、ジェネレータ関数によって作成されたことを「ジェネレータイテレータ」として表記する。

 前回作成したイテレータは、__iter__メソッドと__next__メソッドを持つクラスとして定義した。これに対して、ジェネレータ関数は(その名の通り)関数の形で定義する。ただし、通常の関数とジェネレータ関数には大きな違いがある。

 まず、通常の関数は、それを呼び出せば、その本体に記述したコードが実行されて、その結果が戻されるが、ジェネレータ関数を呼び出すと、戻ってくるのは、ジェネレータイテレータと呼ばれるオブジェクトであることだ(Pythonの処理系がジェネレータ関数の定義を処理する際に、そのように特別扱いしてくれる)。

ジェネレータ関数とジェネレータイテレータジェネレータ関数とジェネレータイテレータ

 作成されたジェネレータイテレータはイテレータなので、__iter__メソッドや__next__メソッドを持ち、前回見たイテレータを置ける場所(つまり、反復可能オブジェクトを置ける場所の大半)にそれを置けるようになっている。このとき、ジェネレータ関数定義の本体はおおよそ__next__メソッドの内容と考えられる。また、ジェネレータ関数により生成されたジェネレータイテレータが、本体に記述したコードの実行を制御するようになっている。

 もう一つ、関数はそれを呼び出すごとに、本体に記述されたコードが一度実行され、return文で戻り値を返すか、あるいは関数末尾まで到達すると、そこで関数の実行が終了する。これに対して、ジェネレータ関数がその呼び出し側に値を返すには、return文ではなく「yield式」を使うところも大きな違いだ。しかも、ジェネレータ関数の本体に書いたコードは、呼び出し側に値を何度も返せる。この辺は文字で説明するよりもコードで見ていただいた方が理解が早いので、まずは簡単なジェネレータ関数を定義して、その動作を見てみよう。

簡単なジェネレータ関数の定義

 簡単なジェネレータ関数の定義を以下に示す。

def simple_generator(): yield 1 yield 2 yield 3

簡単なジェネレータ関数の定義

 既に述べた通り、return文ではなく、「yield 値」という「yield式」が書かれていることが分かる。これが文ではなく、式であることには理由があるが、それについては後で見よう。ここでは、yield式で呼び出し側に値を返せることを覚えておけばよい。そして、上で「呼び出し側に値を何度も返せる」と書いたことに対応するのが、yield式が3つ並んでいる点だ。

 では、上のコードで定義したsimple_generator関数(と、それが返すジェネレータイテレータ)の使い方を見ていく。

 まずは、ジェネレータ関数を呼び出して、ジェネレータイテレータを取得するところから始めよう。

mygeniter = simple_generator()print(type(mygeniter)) # simple_generator関数の戻り値の型を調べるprint('__iter__' in dir(mygeniter)) # __iter__メソッドがあるかprint('__next__' in dir(mygeniter)) # __next__メソッドがあるか

ジェネレータ関数の呼び出しとジェネレータイテレータの取得

 最初の行では、上で定義したジェネレータ関数を呼び出している。その戻り値であるジェネレータイテレータが変数mygeniterに代入される。2行目では、その型を調べている。3行目と4行目では、ジェネレータイテレータに本当に__iter__メソッドと__next__メソッドがあるかどうかを確認している。

 このコードを実行すると次のようになる。

実行結果実行結果

 ご覧の通り、simple_generator関数の戻り値の型は「generator」になっている(このことから、ジェネレータイテレータのことを単に「ジェネレータ」と呼ぶことがあるのだろう)。また、その下の出力はいずれもTrueであることから、これがイテレータであることも確認できた。この__next__メソッドから、ジェネレータイテレータのコード(ジェネレータ関数定義の本文として記述したコード)が実行される。

 ジェネレータ関数の戻り値がイテレータであることが分かったので、next関数にこれを渡したり、__next__メソッドを呼び出したりしてみよう。

print(next(mygeniter)) # 次の値を取得print(mygeniter.__next__()) # 次の値を取得print(next(mygeniter)) # 次の値を取得print(mygeniter.__next__()) # 次の値を取得

simple_generator関数の使用例

 これを実行すると、次のようになる。

実行結果実行結果

 「yield 1」「yield 2」「yield 3」という3つのyield式に渡している整数値が順番に返された後にStopIteration例外が発生している。

 通常の関数では、その定義の本体に書いたコードは関数末尾に到達するか、どこかでreturn文に到達するまで実行が続けられる。これに対して、ジェネレータ関数の本体に書いたコードは、そのジェネレータイテレータの__next__メソッドが呼び出されることで実行される。そして、その実行はyield式に到達するまで続けられ、yield式が実行されると、それに渡された値が呼び出し側に戻され、そこでコードの実行が一時停止されるのだ。その後、再び、ジェネレータイテレータの__next__メソッドが呼び出されると、今度は次の行から実行が再開されて、再びyield式に到達するまで実行が続けられる。このような形で、ジェネレータイテレータのコードは実行されることをまずは覚えておこう。

 上のコードなら、以下のような形でジェネレータ関数に記述したコードは実行されているということだ。

ジェネレータイテレータのコードの実行ジェネレータイテレータのコードの実行

 このようにしてコードの実行と中断が繰り返され、最終的にyield式に到達しないままコードの実行が終了したところで、StopIteration例外が発生する。コードが実行/中断されている間の情報(ローカル変数の値や、現在どこのコードを実行しているかなど)はジェネレータイテレータ自身が管理してくれるので、プログラマーが気にする必要はない。

 次に、先ほどのsimple_generator関数のコードを次のように変更してみよう。

def simple_generator(): yield 1 print('first yield expression done') yield 2 print('second yield expression done') yield 3 print('third yield expression done')

修正したsimple_generator関数

 そして、今度はnext関数(__next__メソッド)を一度だけ呼び出してみよう。

mygeniter = simple_generator()print(next(mygeniter)) # 次の値を取得

next関数を一度だけ呼び出してみる

 すると、次のような結果が得られる。

実行結果実行結果

 「first yield expression done」が表示されると思った方もいるかもしれない。しかし、yield式が実行されたところで、実行の制御も呼び出し側に戻るので、直下のprint関数呼び出しは実行されないのだ。そして、もう一度、next関数を呼び出したところで、次の行から実行が再開される。

print(next(mygeniter)) # 次の値を取得

もう一度next関数を呼び出してみる

 今度は最初のyield式の次の行が実行されて、次のyield式まで実行が続けられるので、次のような結果になる。

実行結果実行結果

 次に前回に見た0から順にカウントアップしていくだけのイテレータを、ジェネレータ関数を使ってジェネレータイテレータとして書き直してみよう。

カウントアップするジェネレータイテレータ/yield式の値とsendメソッド仮想通貨カジノパチンコパチンコ 屋 川越