1 / 18

Iterator を使おう

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

Download Presentation

Iterator を使おう

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Lightweight Language Weekend ls-lRシェル Iteratorを使おう 日本Pythonユーザ会 石本 敦夫

  2. Lightweight Language Weekend ls-lRシェル Iterator パターン • GoFによる定義 集約オブジェクトが基にある内部表現を公開せずに、その要素に順にアクセスする方法を提供する Iterator Collection Item

  3. Lightweight Language Weekend ls-lRシェル Pythonのイテレータ • データやアルゴリズムをイテレータでラップし、シーケンスのように順にデータを取得する方法を提供する Iterator Collection Function File etc,...

  4. Lightweight Language Weekend ls-lRシェル Pythonのイテレータ サポート • Pythonのステートメントはイテレータを使用するように変更されている

  5. Lightweight Language Weekend ls-lRシェル イテレータインターフェース • Iterable - イテレート可能オブジェクト • 組み込み関数 iter()を使ってイテレータを取得することができるオブジェクト • for文などで直接使用することができる • Python組み込みのコンテナはすべてIterable • イテレータを返すメソッド__iter__() を持つ • iterator – イテレータオブジェクト • 次の値を返すnext()メソッドを持つ • next()で返すオブジェクトがなければ、StopIteration例外を送出する • __iter__()メソッドを持ち、自分自身を返す

  6. Lightweight Language Weekend ls-lRシェル イテレータの例 • Fileイテレータ - ファイルを行のシーケンスとみなし、順に読み込む inFile = open("./foo.txt") for line in inFile: print line # 又は inFile = open("./foo.txt") fileIter = iter(inFile) print fileIter.next() print fileIter.next()

  7. Lightweight Language Weekend ls-lRシェル イテレータの実装例 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()は最低限必要 • 次回の呼び出しに備えて状態を保存しなければならない

  8. Lightweight Language Weekend ls-lRシェル 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

  9. Lightweight Language Weekend ls-lRシェル イテレータのメリット • 実際にシーケンスを作成する必要がないため効率が良い • 無限長のシーケンスを扱う事ができる • 呼び出し元の処理がシンプルになる • データを取り出すタイミングを呼び出し元で制御できる • forループ内で終了条件をチェックする必要がないため、処理がすっきりする

  10. Lightweight Language Weekend ls-lRシェル Generator関数 • 関数定義の形でイテレータを定義 • Generator関数は戻り値としてイテレータを返す • イテレータのnext()は、yield文で指定した値を次々に返す • # return ('最初', '2番目', '終わり' )と同じ • def gen(): • yield '最初' • yield '2番目' • yield '終わり' • # Generetor関数 の呼び出し • v = gen() • print v.next(), # '最初' • print v.next(), # '2番目' • print v.next(), # '終わり' • # 又は • for v in gen(): • print v, • # 出力 => 最初 2番目 終わり

  11. Lightweight Language Weekend ls-lRシェル Generatorの動作 • 呼び出されると イテレータの一種であるgeneratorオブジェクトを返す • generatorのnext()メソッドを呼び出すと、関数のyield文までを実行してその値を返す • yield文に遭遇せずに関数が終了すると、StopIteration例外を送出する 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 def gen(): yield 'a' yield 'b' 同じ

  12. Lightweight Language Weekend ls-lRシェル Generatorのメリット • 簡単にイテレータを作成する事ができる • 処理状態をどこかに退避する必要がない • 速い! • クラスを使ったイテレータより100%以上速いケースも • ほとんどローカル変数のみで実行できる • 状態を退避する必要がない

  13. Lightweight Language Weekend ls-lRシェル Generator版AlterIter def AlterIter(seq1, seq2): _max = min(len(seq1), len(seq2)) for idx in range(_max): yield seq1[idx] yield seq2[idx] • イテレータクラスより簡単 • 高速!

  14. Lightweight Language Weekend ls-lRシェル 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 ...

  15. Lightweight Language Weekend ls-lRシェル イテレータの合成 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,

  16. Lightweight Language Weekend ls-lRシェル パフォーマンス比較 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)) 測定環境: Python2.3.3 Windows2000 結果 • イテレータの二段重ねでもそれほど遅くはならない • 柔軟性とのトレードオフ

  17. Lightweight Language Weekend ls-lRシェル 参考リンク • PEP 234 Iterators http://www.python.org/peps/pep-0234.html • PEP 255 Simple Generators http://www.python.org/peps/pep-0255.html

  18. Lightweight Language Weekend ls-lRシェル 終わりに • イテレータを使おう。イテレータはPythonicだ。 • Generatorを使おう。Generatorは魔法じゃない。

More Related