Presentation is loading. Please wait.

Presentation is loading. Please wait.

Lightweight Language Weekend ls-lRシェル

Similar presentations


Presentation on theme: "Lightweight Language Weekend ls-lRシェル"— Presentation transcript:

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

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

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

4 Pythonのイテレータ サポート Pythonのステートメントはイテレータを使用するように変更されている Python2.1以前
Lightweight Language Weekend ls-lRシェル Pythonのイテレータ サポート Pythonのステートメントはイテレータを使用するように変更されている Python2.1以前 Python2.2以降 for i in [1,2,3]: print i seq = [1,2,3] n = 0 while True: try: print seq[n] except IndexError: break n += 1 iterator = [1,2,3].__iter__() i = iterator.next() except StopIteration: i, j = (1,2) seq = (1,2) i = seq[0] j = seq[1] iterator = (1,2).__iter__() j = iterator.next()

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

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

7 イテレータの実装例 class AlterIter: '''seq1, seq2内の要素を交互に返すイテレータ'''
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 AlterIterの使用方法 for ステートメントでイテレータを使用する もちろん、next()メソッドで順次読み出しても良い
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(),

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

10 Generator関数 関数定義の形でイテレータを定義 Generator関数は戻り値としてイテレータを返す
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 Generatorの動作 呼び出されると イテレータの一種であるgeneratorオブジェクトを返す
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 Generatorのメリット 簡単にイテレータを作成する事ができる 処理状態をどこかに退避する必要がない 速い!
Lightweight Language Weekend ls-lRシェル Generatorのメリット 簡単にイテレータを作成する事ができる 処理状態をどこかに退避する必要がない 速い! クラスを使ったイテレータより100%以上速いケースも ほとんどローカル変数のみで実行できる 状態を退避する必要がない

13 Generator版AlterIter イテレータクラスより簡単 高速! def AlterIter(seq1, seq2):
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 Fibonacci数列 def fibonacci(): i = j = 1 yield i yield j while True:
Lightweight Language Weekend ls-lRシェル Fibonacci数列 def fibonacci(): i = j = 1 yield i yield j while True: i, j = j, i+j for n in fibonacci(): print n, 出力 =>

15 イテレータの合成 def odds(iterable): '''奇数のみを返すイテレータ''' for v in iterable:
Lightweight Language Weekend ls-lRシェル イテレータの合成 def odds(iterable): '''奇数のみを返すイテレータ''' for v in iterable: if v % 2: yield v def lessThan(iterable, cond): '''cond以下の値のみを返すイテレータ''' if v < cond: seq = [90, 22, 49, 93, 49, 68, 36, 96, 31, 23] for v in odds(lessThan(seq, 50)): print v,

16 パフォーマンス比較 イテレータの二段重ねでもそれほど遅くはならない 柔軟性とのトレードオフ 結果 test1() test2()
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): def test3(seq, f): if f(v): # テスト用シーケンス seq = [random.randint(0, 10000) for v in range( )] test1(seq) test2(seq) test3(seq, lambda v: (v < 50) and (v % 2)) 測定環境: Python2.3.3 Windows2000 結果 test1() test2() test3() 0.72秒 0.59秒 1.08秒 イテレータの二段重ねでもそれほど遅くはならない 柔軟性とのトレードオフ

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

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


Download ppt "Lightweight Language Weekend ls-lRシェル"

Similar presentations


Ads by Google