試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

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

関連記事:

使用したバージョン:

*1:戻り値のあるreturn文では「SyntaxError: 'return' with argument inside generator」になる