Jintrick.netagenda2003年11月アーカイブ → 2003年11月13日

ジェネレータを理解

この「ジェネレータを使ったバージョン」がようやく理解できた。

def fg(args):
  if not args:
    yield ""
    return
  for i in args[0]:
    for tmp in fg(args[1:]):
      yield i + tmp
  return

このreturnに何か意味があるのかと思って苦戦。少なくともここでは意味は無いようなのでとっぱらって、さらにどこでgeneratorが「凍結」しているのか分かりやすくするために、for in文内の暗黙的なものを明示的に書いてみた。

def h(args):
    if not args:
        yield ""
    else:
        for i in args[0]:
            gen = h(args[1:])
            itr = gen.__iter__()
            while 1:
                try:
                    tmp = itr.next()
                except StopIteration:
                    break
                yield i + tmp

この関数hは、評価されるとgeneratorオブジェクト(gen)を返す。で、genのnextメソッドが呼ばれた時(gen.__iter__()は恐らく自分自身を返しているので、gen.__iter__().next() は gen.next()と同じ)、初めて関数の中身を評価するのだけれども、yield文(returnのように値を返す)を実行した時点の状態で凍結し、次回にnextメソッドが呼ばれるまでその状態を保持している。だから、StopIteration例外が発生するまではwhile 1:ループの中にいることになる。

nextメソッドの呼び出しと例外の発生が隠蔽されて、頭の中でループを追いかけている最中にどこで凍結しているのか分からなくなっていたのが理解しづらかった原因らしい。で、rdflibのソースコードが異常にシンプルなのにさっぱり意味不明だったのはこのgeneratorが原因だったわけで、ようやく色々弄れるようになった。

というか検索用にPython。


webmaster@jintrick.net
公開: 2003年11月13日
カテゴリ: Python