Help us understand the problem. What is going on with this article?

【Python】ジェネレータ(generator)関数

はじめに

 この記事はジェネレータ(generator)関数を理解せずに使用して失敗したため, ジェネレータ(generator)関数の勉強のための記事になります. 内容は, 参考文献を用いた自分用の備忘録です.

定義

 まずはジェネレータ関数の定義を確認する.

  • 定義:ジェネレータ関数1

関数定義の中でyield文が使われている場合、その関数はジェネレータ関数と呼ばれます。ジェネレータ関数はイテレータの一種です。

例:
 yieldを使ったジェネレータ関数をPython3.7.4で実行. yieldにより区切られて値が返されます.

def sample_generator_fun():
    yield 1
    yield 2
    yield 3

check = sample_generator_fun()
print(check.__next__())
print(check.__next__())
print(check.__next__())

 実行結果

1
2
3

 さらにcheckを実行すると...

print(check.__next__())
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-25-7029da5797f2> in <module>
----> 1 print(check.__next__())

StopIteration:

 反復停止と表示され, エラーとなります. つまり, sample_generator_funのyield文が順に実行され, 3番目の「yield 3」が実行されると反復が終了され, さらに実行しても値を返しません.

失敗例

 ジェネレータ関数をきちんと理解せず, リストなどのイテレータオブジェクトと同じものとして考え, 下記の様な失敗をしました. ※そもそも, 恥ずかしながらジェネレータ関数の存在を知りませんでした

例:
 取得されたジェネレータ関数のイテレータ数が2超であるのかを確認し, そうであれば実行する.

 失敗例

check = sample_generator_fun()

if len(list(check)) > 2:
    print("True")
    for i in check:
        print(i)
else:
    print("False")

 実行結果

True

 ここで, 私はif文でTrueになっているのに, なぜその下のfor文が実行されないのか悩み, 色々と調べてジェネレータ関数にたどり着くことが出来ました. 条件式内のlist(check)を実行したことで, 最後の「yield 3」まで実行されたことになるので, 次のfor文ではcheckは値を返さないため, for文は実行されません.

解決策

 簡単に思いつく範囲で下記2つが挙げられます. 工夫してジェネレータ関数を複数回呼び出し可能にする場合は, この記事2の様にするのが良いかもしれません.

  • ジェネレータ関数で返される総データサイズが大きくなければ, リストに変換して使用する
check = sample_generator_fun()
check_list = list(check)

if len(check_list) > 2:
    print("True")
    for i in check_list:
        print(i)
else:
    print("False")

 実行結果

True
1
2
3
  • 単純に2回, ジェネレータ関数を呼び出す. この場合はジェネレータ関数のメリットであるメモリの節約は保持されます
check = sample_generator_fun()

n = 0
for i in check:
    n += 1
    if n > 2:
        print("True")
        check = sample_generator_fun()
        for j in check:
            print(j)
        break
else:
    print("False")

 実行結果

True
1
2
3

感想

 スクリプト言語では型宣言などをしなくてもコードを書けますが, どんな型やどんな性質のオブジェクトを触っているのかは, きちんと把握していないと事故りますね. 今回は「リスト」と同様だろうなという希望的観測による失敗でした. 使用するライブラリの中身を全て把握するのは難しいですが, 今回のような基本的なことはきちんと正確に抑えるべきだと改めて痛感しました.


  1. 中久喜健司:科学技術計算のためのPython入門, 2016年, 技術評論社 

  2. Python のジェネレータを何回もイテレートしたい 

ryotaro-sano
数学, 統計, 機械学習, プログラム(R, Python, C)を中心とした備忘録. また, 競馬予測AI Nimbaの開発記録.
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした