2015/11/24

Python のイテレータ生成クラスの使い方

今回は Python のイテレータ生成クラスを使う方法についてご紹介します。

Python でイテレータ( iterator )を生成する関数のことを「ジェネレータ」( generator )と呼びますが、関数と同様にクラスを使う形でもイテレータを生成することができます。

具体的には、 __iter__() メソッドを定義してこれがイテレータを返すようにすれば OK です。その最もかんたんな方法は yield を使う方法です。

逆に yield を使わない場合は __iter__() に加えて __next__() ( Python 2 の場合は next() )メソッドを定義する必要がありますが、シンプルなケースでは __iter__()yield を使った方法がシンプルかつかんたんです。

サンプルとして、与えられた整数の因数を返すジェネレータクラスを見てみましょう。

# 因数を返すイテレータクラス
class PrimeFactor(object):
   
    // number で対象の数を、 max_count で返す因数の数を指定する
    def __init__(self, number, max_count):
        self.number = number
        self.max_count = max_count

    // インスタンスをジェネレータ化する
    def __iter__(self):
        count = 0
        for i in range(2, self.number):
            if self.number % i == 0:
                count += 1
                // 指定された数だけ因数が返されたらイテレータ処理を終了するために StopIteration() 例外をあげる
                if count > self.max_count:
                    raise StopIteration()
                yield i

ここで定義した PrimeFactor は以下の形で使うことができます。

pf = PrimeFactor(number = 100, max_count = 5)

# 1 周目
for n in pf:
    print(n, end=", ")
print()
# => 2, 4, 5, 10, 20,

# 2 周目
for n in pf:
    print(n, end=", ")
print()
# => 2, 4, 5, 10, 20,

この形で定義されたイテレータ生成オブジェクトは、何度もループで回せるという特徴があります(処理の内容にもよりますが)。一方、ジェネレータ関数で生成されたオブジェクトの場合、ループで回せるのは一般に一度かぎりです。

# PrimeFactor の関数版
def prime_factor(number, max_count):
    count = 0
    for i in range(2, number):
        if number % i == 0:
            count += 1
            if count > max_count:
                raise StopIteration()
            yield i

# こちらはいったんループを回したらその後は StopIteration 例外を出し続けるため
# 2 周目のループは実行されない
pf2 = prime_factor(number = 100, max_count = 5)

# 1 周目
for n in pf2:
    print(n, end=", ")
print()
# => 2, 4, 5, 10, 20,

# 2 周目
for n in pf2:
    print(n, end=", ")
print()
# => 出力なし

ちなみに、この、イテレータを返すオブジェクトのことをイテラブル( iterable )と呼ぶそうです。

以上です。

参考

0 件のコメント: