2008-12-17
■ [Python] イテレータとジェネレータ(5)

この間の続きだよ。
前回の例で、
- 関数定義中にひとつでもyield文を書くと、その関数はジェネレータ関数になる
- ジェネレータ関数を評価するとジェネレータが返る
- そのジェネレータに対してnext()メソッドを実行すると関数の実行が始まり、yield文のところで関数の呼び出し元に返る
ということがわかったよ。
前回の例ではyield文のあとに何も書いていなかったけど、yield文に続いて式を記述しておくと、next()メソッドの呼び出し元にその評価結果を返すことが出来るよ。というか、ジェネレータは元々「値の生成器」だから値を返すのは当然だよね。
じゃあ、値が返るジェネレータの例だよ。next()メソッドを呼ぶたびにyield文が逐次実行されていき、戻り値が適宜返ってきていることが分かるよ。
>>> def fire():
yield 3
yield 2
yield 1
yield 'Fire!'
>>> g = fire()
>>> g.next()
3
>>> g.next()
2
>>> g.next()
1
>>> g.next()
'Fire!'
>>> g.next()
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
g.next()
StopIteration
>>>
こんな感じでyield文をいくつも書くのは大変だから、通常のジェネレータ関数の場合はループの中にyield文を書くよ。たとえばフィボナッチ数列を生成するジェネレータ関数は次のようになるよ。
>>> def fibo(n):
i, j = 0, 1
for x in range(n):
yield i
i, j = j, i + j
>>> g = fibo(10)
>>> g.next()
0
>>> g.next()
1
>>> g.next()
1
>>> g.next()
2
>>> g.next()
3
>>> g.next()
5
>>> g.next()
8
>>> g.next()
13
>>> g.next()
21
>>> g.next()
34
>>> g.next()
Traceback (most recent call last):
File "<pyshell#93>", line 1, in <module>
g.next()
StopIteration
>>>
ついでに、みんな大好きFizzBuzz問題をジェネレータを使って解いてみるよ。
>>> def fizzbuzz(n): for i in range(1, n + 1): if i % 15 == 0: yield "FizzBuzz" elif i % 5 == 0: yield "Buzz" elif i % 3 == 0: yield "Fizz" else: yield i >>> for x in fizzbuzz(100): print x (実行結果省略)
コメント
トラックバック - http://python.g.hatena.ne.jp/muscovyduck/20081217