Pythonのジェネレータについて
PyGTKでのプログレスバーについて調べていたところでジェネレータという馴染みのない概念が出てきたので、先にこちらをまとめておく。
挙動について
- 関数と似た形で記述される
- 値を返すには(return文でなく)yield文を使用
- 「g = generator()」のような操作を行ったところでは処理は呼ばれず、ジェネレータオブジェクトというものが返る
- このオブジェクトのメンバ関数next()が呼ばれると、最初のyield文までの処理が行われる
- yieldの後ろの値がnext()の戻り値として返る
- 処理はyield文までで一旦止まり、中の変数や現在の位置は保持される
- 次にnext()が呼ばれるとそこから処理が再開されて、次にyield文が出るところまで続く(以下同様)
- yield文が見つからずにジェネレータの終わりに到達するか、戻り値のないreturn文*1が見つかると、StopIterationという例外が出る
- 用途としては、それ自身を繰り返し呼び出す形(再帰)の処理を簡単に扱えるらしい
参考URL:
テスト
下のコードは、上にまとめた挙動をすることを確かめるために作成したもの。実用的なサンプルではない。
#! /usr/bin/python # -*- encoding: utf-8 -*- def generator_test(): i = 0 str = "abcdefg" while True: if i < len(str): yield str[i] i += 1 else: break str += "h" yield str str += "i" yield str print "(end of generator)" g = generator_test() print "-- begin --" while True: try: print g.next() except StopIteration: # yield文が見つからずに最後に到達 print "(StopIteration)" break print "-- end --" # もう一度はじめから g = generator_test() print "-- begin --" for x in g: # for文で回す print x print "-- end --"
実行結果
-- begin -- a b c d e f g abcdefgh abcdefghi (end of generator) (StopIteration) -- end -- -- begin -- a b c d e f g abcdefgh abcdefghi (end of generator) -- end --
下の例では、ジェネレータの中を無限ループにしている。next()を繰り返し呼ぶと、戻り値は1ずつ延々と増え続ける。
#! /usr/bin/python # -*- encoding: utf-8 -*- def generator_test2(x): while True: yield x x += 1 g = generator_test2(10) # next()を繰り返し呼び続ける限り、無限に続く print g.next() # 10 print g.next() # 11 print g.next() # 12 print g.next() # 13
実行結果
10 11 12 13
関連記事:
使用したバージョン:
- Python 2.4.4(2.4.4-r13)
*1:戻り値のあるreturn文では「SyntaxError: 'return' with argument inside generator」になる