読者です 読者をやめる 読者になる 読者になる

exits

勉強記録

Pythonで最近好きなこと(2)

技術 Python AdventCalendar

--2016.08.29 他のブログに書いていた記事をこちらに移しました

この記事はKobeUniv Advent Calendar 2015の21日目に書かれたものです.

FPGA

カレンダーの予告コメントで調子に乗ってFPGAとか書いたら先にふっかけられてしまって泣きそうです.cormoranさんGJ.

ここ最近FPGAを触れていないのですが,2年前のインターンのことを思い出してがんばって書いてみよう・・・と思ったのですが,復習する時間がありませんでした.就活つらい.

用もないのに引っ張りだされて不機嫌なDE0nanoさん f:id:yue82:20151221000221p:plain:w300

というわけで今回は,前回の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

ジェネレータの実装

何が違うのか,またジェネレータとはなんなのか試すため,rangexrangeを雑実装してみます.

まず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です.がんばってください.