torinaブログ

DjangoとBootstrap4で作成したブログ
Python, Django, Kivy, Bootstrap, Apache等のメモです
ソースコード

Python、ジェネレータ

Python Python言語仕様
約479日前 2015年11月6日14:20
暇なので早速更新

参考
http://docs.python.jp/3.4/tutorial/classes.html#generators

イテレータオブジェクトを作る方法は自分でクラスを定義する方法と、ジェネレータを使う方法がある

ジェネレータ関数を使う
>>> def my_gen(data):
...     cnt = 0
...     for char in data:
...         yield char + str(cnt)
...         cnt += 1
...
>>> for i in my_gen(`あいうえお`):
...     print(i)
...
あ0
い1
う2
え3
お4

__iter__も__next__も書いてないけど、こいつは立派なイテレータオブジェクトです
>>> gen = my_gen(`あいうえお`)
>>> gen
<generator object my_gen at 0x00702558>
>>> dir(gen)
['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__',
'__hash__', '__init__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_e
x__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 's
end', 'throw']
>>> next(gen)
'あ0'
>>> next(gen)
'い1'
>>> next(gen)
'う2'
>>> next(gen)
'え3'
>>> next(gen)
'お4'
>>> next(gen)
Traceback (most recent call last):
  File `<stdin>`, line 1, in <module>
StopIteration

このように、関数定義内でyieldを書くと勝手に__iter__と__next__を作ってくれるので、for i in spam:というように使えるんですね
おまけに呼び出しごとにローカル変数と実行状態が自動的に保存されるので、self.indexとかの変数を作る手間もいらない

ジェネレータ関数の兄弟にジェネレータ式というものもある
>>> gen = (char + str(index) for index,char in enumerate(`あいうえお`))
>>> gen
<generator object <genexpr> at 0x00702698>
>>> dir(gen)
['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__',
'__hash__', '__init__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_e
x__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 's
end', 'throw']
>>> next(gen)
'あ0'
>>> next(gen)
'い1'
>>> next(gen)
'う2'
>>> next(gen)
'え3'
>>> next(gen)
'お4'
>>> next(gen)
Traceback (most recent call last):
  File `<stdin>`, line 1, in <module>
StopIteration

リスト内包表記とかと同じような書き方で書ける
ジェネレータ関数よりも簡単にかけるけど、難しいことは苦手
あとは「文」ではなく「式」というメリットもあるのかな