--2016.08.29 他のブログに書いていた記事をこちらに移しました
この記事はKobeUniv Advent Calendar 2015の21日目に書かれたものです.
FPGA
カレンダーの予告コメントで調子に乗ってFPGAとか書いたら先にふっかけられてしまって泣きそうです.cormoranさんGJ.
ここ最近FPGAを触れていないのですが,2年前のインターンのことを思い出してがんばって書いてみよう・・・と思ったのですが,復習する時間がありませんでした.就活つらい.
用もないのに引っ張りだされて不機嫌なDE0nanoさん
というわけで今回は,前回のAdvent Calendarに載せた続きとしてPythonについて書きます!すいません!_○/|_
ジェネレータ
というわけでジェネレータの話をします.
range or xrange
例として,Python2.X系でのrangeの話をあげます.Python2.X系ではfor文を回す時などによく使うものとしてrange()
とxrange()
があります.
この時,見た目の挙動は同じです.
>>> for i in range(5): ... print i, 0 1 2 3 4 >>> for i in xrange(5): ... print i, 0 1 2 3 4
しかし,扱いは別です.
>>> range(5) [0, 1, 2, 3, 4] >>> xrange(5) xrange(5)
range()
では,リストが得られますが,xrange()
ではジェネレータが得られています.
なお,xrange()
はPython3.X系では廃止され,range()
でジェネレータが得られるように変更されています.
>>> range(5) range(0, 5) >>> xrange(5) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'xrange' is not defined
ジェネレータの実装
何が違うのか,またジェネレータとはなんなのか試すため,range
とxrange
を雑実装してみます.
まずrange
です.リストを作ります.返します.そんな感じですね.
>>> def myrange(i): ... j = 0 ... l = [] ... while j < i: ... l.append(j) ... j += 1 ... return l ... >>> myrange(5) [0, 1, 2, 3, 4]
次にxrange
です.
>>> def myxrange(i): ... j = 0 ... while j < i: ... yield j ... j += 1 >>> myxrange(5) <generator object myxrange at 0x7f80cfdaceb0> >>> for i in myxrange(5): ... print i, 0 1 2 3 4
ジェネレータができました.
yield
ジェネレータを作るのに使ったのは,yield文です.これは,その関数のその時点での値を返り値とします. わかりやすくするとこんな感じ.
>>> def myxrange(i): ... j = 0 ... while j < i: ... print "in func:", j ... yield j ... j += 1 >>> for i in myxrange(5): ... print "out:", i in func: 0 out: 0 in func: 1 out: 1 in func: 2 out: 2 in func: 3 out: 3 in func: 4 out: 4
next()
ジェネレータはnext()で進めることも出来ます.
>>> a = myxrange(5) >>> a.next() in func: 0 0 >>> a.next() in func: 1 1 >>> a.next() in func: 2 2 >>> a.next() in func: 3 3 >>> a.next() in func: 4 4 >>> a.next() Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
イテレートが終わるとStopIteration例外がraiseされます.
この辺りJava勢には納得かも?
イテレータ?
wikipedia曰く.
ジェネレータの語は、「yield文を含む関数定義により定義された関数」と、それが返す「イテレータと同じインタフェースを持つ呼び出し可能オブジェクト」を、はっきりと区別せずに使われているが、ここでは、前者をジェネレータ、後者をイテレータと呼ぶ。
つまり,ジェネレータは関数(の定義),イテレータは(イテレート可能な)オブジェクトなんですかね.
無理やりクラスで例えるなら,ジェネレータがクラス定義,イテレータはインスタンス・・・?(自信ない)
itertools
ともかく有用なイテレータはitertoolsというモジュールに入ってます.こないだ使ったのは直積を求めるproduct
ですね.
>>> import itertools >>> a = itertools.product([1, 2, 3], [4, 5]) >>> for b in a: ... print b (1, 4) (1, 5) (2, 4) (2, 5) (3, 4) (3, 5)
ジェネレータの良い所
メモリを無駄遣いしません.リストとして保持しておく必要のない,ループのためだけに存在するような一時的なリストについては,ジェネレータを使ったほうがよいです.
とりあえずそんな感じでした(・ω・)
その他
- cormoranさんは僕の(元いた)サークルの後輩にもあたるようです.GJです.がんばってください.