Pythonにおけるイテレータとジェネレータの実装と活用

Pythonでは、コレクション内の要素を順に処理する仕組みとしてイテレータ(iterator)とジェネレータ(generator)が提供されています。これらはメモリ効率やコードの可読性を高める上で重要な役割を果たします。

イテレータの基本

イテレータは、現在の走査位置を記憶できるオブジェクトであり、__iter__()__next__() の2つの特殊メソッドを実装することでカスタムイテレータを作成できます。

組み込み型(リスト、タプル、文字列など)は既にイテラブルであり、iter() を使ってイテレータに変換可能です:

data = [10, 20, 30]
it = iter(data)
print(next(it))  # 10
print(next(it))  # 20

また、for ループでも自然に使用できます:

for val in iter([10, 20, 30]):
    print(val, end=' ')  # 出力: 10 20 30

カスタムイテレータの実装

クラスでイテレータを実装するには、以下の例のように __iter__()__next__() を定義します:

class Counter:
    def __init__(self, limit):
        self.limit = limit

    def __iter__(self):
        self.current = 0
        return self

    def __next__(self):
        if self.current < self.limit:
            value = self.current
            self.current += 1
            return value
        else:
            raise StopIteration

# 使用例
counter = Counter(3)
for num in counter:
    print(num)  # 0, 1, 2

StopIteration 例外は、イテレーションの終了を示すために必須です。これにより無限ループを回避できます。

ジェネレータによる遅延評価

ジェネレータは、yield キーワードを含む関数として定義され、呼び出されるとイテレータを返します。実行は yield で一時停止し、次回の呼び出し時にその続きから再開されます。

以下は、数値を逆順に生成するシンプルなジェネレータの例です:

def reverse_count(start):
    while start > 0:
        yield start
        start -= 1

gen = reverse_count(4)
print(next(gen))  # 4
print(next(gen))  # 3

# 残りをforループで取得
for n in gen:
    print(n)  # 2, 1

フィボナッチ数列のジェネレータ実装

ジェネレータは無限または大きなシーケンスをメモリ効率よく扱うのに適しています。以下はフィボナッチ数列を生成する例です:

def fib_sequence(n_terms):
    a, b = 0, 1
    count = 0
    while count < n_terms:
        yield a
        a, b = b, a + b
        count += 1

# 最初の10項を出力
for val in fib_sequence(10):
    print(val, end=' ')  # 0 1 1 2 3 5 8 13 21 34

このように、ジェネレータは必要になるまで値を生成しないため、大規模データ処理において非常に有用です。

タグ: Python Iterator Generator yield StopIteration

5月28日 20:37 投稿