python3.3のyield fromとは何なのか

python3.4で追加されたasyncioで使われているyield fromってやつ。 python3.3のWhat's Newを見てたら出てきたのでびっくりしました。 asyncio専用の構文じゃないんですねあれ。

で、そのyield fromの使い方。

def range_ten():
    yield from range(10)

if __name__ == '__main__':
    for i in range_ten():
        print(i)

例えばこんな感じ。0から9までを返す専用のrange的なもの。

def range_skip():
    yield from range(0, 5)
    yield from range(10, 15)

if __name__ == '__main__':
    for i in range_skip():
        print(i)

こうすると、0から4、少し飛ばして10から14までを表示する。

ジェネレータ関数もreturnを書くことができる。

>>> def tea():
...	yield from range(0, 3)
...	return 'hello'
...
>>> tuple(tea())
(0, 1, 2)

こう書くと意味がなさそうだけれど、以下のようにすると取り出せる。

>>> def teb():
...	x = yield from tea()
...	print(x)
...
>>> tuple(teb())
hello
(0, 1, 2)

asyncioのコードっぽくなってきた。奇妙だ。 ちなみに、print(yield from tea())は動きませんでした。SyntaxErrorだってさ。

この手の構文活用してイテレータばりばり使ったら、かなりfor文消せそうですよね。結構な勢いで高速化できるはず。

おまけ。FizzBuzzを返すイテレータ。

import itertools

def fizzbuzz():
    yield from map(lambda x: 'Fizz'*(x%3==0) + 'Buzz'*(x%5==0) or str(x), itertools.count(1))