iterator を使おう

18
Copyrightc2004PythonJapan User's Group. Lightweight Lang uage Weekend ls- lRシシシ Iterator をををを シシ Python シシシシ シシ シシ

Upload: anika-salazar

Post on 01-Jan-2016

31 views

Category:

Documents


0 download

DESCRIPTION

Iterator を使おう. 日本 Python ユーザ会 石本 敦夫. Iterator パターン. GoF による定義 集約オブジェクトが基にある内部表現を公開せずに、その要素に順にアクセスする方法を提供する. Iterator. Collection. Item. Python のイテレータ. データやアルゴリズムをイテレータでラップし、シーケンスのように順にデータを取得する方法を提供する. Iterator. Collection. Function. File. etc,. Python のイテレータ サポート. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Iterator を使おう

Copyrightc2004Python JapanUser'sGroup.

Lightweight Language Weekend ls-lRシェル

Iterator を使おう

日本 Python ユーザ会 石本 敦夫

Page 2: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

Iterator パターン• GoF による定義

集約オブジェクトが基にある内部表現を公開せずに、その要素に順にアクセスする方法を提供する

CollectionIterator

Item

Page 3: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

Python のイテレータ• データやアルゴリズムをイテレータで

ラップし、シーケンスのように順にデータを取得する方法を提供する

CollectionIterator

Function

File

etc,...

Page 4: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

Python のイテレータ サポート

Python2.1 以前 Python2.2 以降for i in [1,2,3]: print i

seq = [1,2,3]n = 0while True: try: print seq[n] except IndexError: break n += 1

iterator = [1,2,3].__iter__() while True: try: i = iterator.next() except StopIteration: break print i

i, j = (1,2) seq = (1,2)i = seq[0]j = seq[1]

iterator = (1,2).__iter__()i = iterator.next()j = iterator.next()

• Python のステートメントはイテレータを使用するように変更されている

Page 5: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

イテレータインターフェース• Iterable - イテレート可能オブジェクト

– 組み込み関数 iter() を使ってイテレータを取得することができるオブジェクト

– for 文などで直接使用することができる– Python 組み込みのコンテナはすべて Iterable– イテレータを返すメソッド __iter__() を持つ

• iterator – イテレータオブジェクト– 次の値を返す next() メソッドを持つ– next() で返すオブジェクトがなければ、 StopIteration

例外を送出する– __iter__() メソッドを持ち、自分自身を返す

Page 6: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

イテレータの例• File イテレータ - ファイルを行のシーケンスと

みなし、順に読み込むinFile = open("./foo.txt")for line in inFile: print line

# 又はinFile = open("./foo.txt")fileIter = iter(inFile)print fileIter.next()print fileIter.next()

Page 7: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

イテレータの実装例class AlterIter: '''seq1, seq2 内の要素を交互に返すイテレータ ''' def __init__(self, seq1, seq2): self._seqs = (seq1, seq2) self._cur = 0 self._max = min(len(seq1), len(seq2)) # 最大インデックス値

def __iter__(self): return self

def next(self): n, idx = self._cur % 2, self._cur//2 if idx >= self._max: raise StopIteration # iterate 終了 ret = self._seqs[n][idx] self._cur += 1 return ret

• 通常、 __init__(), __iter__(), next() は最低限必要

• 次回の呼び出しに備えて状態を保存しなければならない

Page 8: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

AlterIter の使用方法• for ステートメントでイテレータを使用する

for v in AlterIter([1,2],['a','b']): print v,

出力 => 1 a 2 b

• もちろん、 next() メソッドで順次読み出しても良いvalues = AlterIter([1,2],['a','b'])print values.next(),print values.next(),print values.next(),print values.next(),

出力 => 1 a 2 b

Page 9: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

イテレータのメリット• 実際にシーケンスを作成する必要がない

ため効率が良い• 無限長のシーケンスを扱う事ができる• 呼び出し元の処理がシンプルになる

– データを取り出すタイミングを呼び出し元で制御できる

– for ループ内で終了条件をチェックする必要がないため、処理がすっきりする

Page 10: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

Generator 関数• 関数定義の形でイテレータを定義• Generator 関数は戻り値としてイテレータを返す• イテレータの next() は、 yield 文で指定した値を次々に返す

# Generetor 関数 の呼び出しv = gen()print v.next(), # ' 最初 'print v.next(), # '2 番目 'print v.next(), # ' 終わり '# 又はfor v in gen(): print v,

# 出力 => 最初 2 番目 終わり

# return (' 最初 ', '2 番目 ', ' 終わり ' ) と同じ

def gen(): yield ' 最初 ' yield '2 番目 ' yield ' 終わり '

Page 11: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

Generator の動作• 呼び出されると イテレータの一種である generator オ

ブジェクトを返す• generator の next() メソッドを呼び出すと、関数の yield

文までを実行してその値を返す• yield 文に遭遇せずに関数が終了すると、 StopIteration

例外を送出する

def gen():

yield 'a'

yield 'b'

class gen: def __init__(self): self._n = 0 def __iter__(self): return self def next(self): if self._n == 0: return 'A' if self._n == 1: return 'B' raise StopIteration

同じ

Page 12: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

Generator のメリット• 簡単にイテレータを作成する事ができる• 処理状態をどこかに退避する必要がない• 速い!

– クラスを使ったイテレータより 100% 以上速いケースも

– ほとんどローカル変数のみで実行できる– 状態を退避する必要がない

Page 13: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

Generator 版 AlterIter

def AlterIter(seq1, seq2): _max = min(len(seq1), len(seq2)) for idx in range(_max): yield seq1[idx] yield seq2[idx]

• イテレータクラスより簡単• 高速!

Page 14: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

Fibonacci 数列def fibonacci(): i = j = 1 yield i yield j while True: i, j = j, i+j yield j

for n in fibonacci(): print n,

出力 => 1 1 2 3 5 8 13 21 34 55 89 ...

Page 15: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

イテレータの合成def odds(iterable): '''奇数のみを返すイテレータ ''' for v in iterable: if v % 2: yield v

def lessThan(iterable, cond): '''cond 以下の値のみを返すイテレータ ''' for v in iterable: if v < cond: yield v

seq = [90, 22, 49, 93, 49, 68, 36, 96, 31, 23]for v in odds(lessThan(seq, 50)): print v,

Page 16: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

パフォーマンス比較def test1(seq):

for v in lessThan(odds(seq), 50):

pass

def test2(seq):

for v in seq:

if (v % 2) and (v < 50):

pass

def test3(seq, f):

for v in seq:

if f(v):

pass

# テスト用シーケンスseq = [random.randint(0, 10000)

for v in range(1000000)]

test1(seq)

test2(seq)

test3(seq, lambda v: (v < 50) and (v % 2))

test1() test2() test3()

0.72秒 0.59秒 1.08秒

結果測定環境:Python2.3.3Windows2000

•イテレータの二段重ねでもそれほど遅くはならない

•柔軟性とのトレードオフ

Page 17: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

参考リンク• PEP 234 Iterators

http://www.python.org/peps/pep-0234.html

• PEP 255 Simple Generatorshttp://www.python.org/peps/pep-0255.html

Page 18: Iterator を使おう

Lightweight Language Weekend ls-lRシェル

Copyrightc2004Python JapanUser'sGroup.

終わりに• イテレータを使おう。イテレー

タは Pythonicだ。• Generator を使おう。 Generator

は魔法じゃない。