オブジェクトの要素を一つずつ取り出す
反復可能なオブジェクト
for i in x: print i l = [n for n in x if n % 2]
x は要素を一つずつ取り出せる反復可能なオブジェクトです。反復可能なオブジェクトは __iter__() でイテレータオブジェクトを返す必要があります。
class Test: def __iter__(self): return self.__dict__.iteritems()
__dict__ はオブジェクトの属性の辞書、iteritem() はキーと値のタプルを返すイテレータオブジェクトを返します。
t = Test() t.s = 1 t.a = 2 t.y = 3 for kv in t: print "%s => %s" % kv
a => 2 y => 3 s => 1
イテレータオブジェクト
イテレータオブジェクトは反復可能なオブジェクトですが、__iter__() で自分自身を返し、次の要素を返す next() を持つ必要があります。next() は最後の要素を返した後は、何度呼び出しても StopIteration 例外を投げなければなりません。そうしないと無限ループになってしまいます。
では、0〜n までの素数を返すイテレータオブジェクトを作ってみます。
import math class Prime: def __init__(self, n): self.nums = range(2, n+1) self.root_n = math.sqrt(n) def __iter__(self): return self def next(self): if len(self.nums): # 1回目のpは2、つまり素数 p = self.nums.pop(0) if self.root_n > p: # 素数pで割り切れる要素を全て取り除く # これでself.numsの先頭は次の素数になる self.nums = [n for n in self.nums if n % p] return p raise StopIteration
まず素数で始まる数値のリストを用意します。そして、next() が呼ばれるたびにリストの先頭の要素を返し、。同時にリストからその要素で割り切れる数を取り除きます。こうするとリストの先頭の要素は必ず素数になります。また、n以下の素数でない数は必ず√n で割り切れるので、素数で要素を取り除くは、先頭の要素が√n 以下の間だけです。
p = Prime(100) print [n for n in p]
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]