Pythonイテレータ入門

イテレータとは?

Pythonにおけるイテレータとは、反復処理を行うことができるオブジェクトのことを指します。イテレータは数えられる値から構成され、これらの値を1つずつ順にたどることができます。

イテレータは、Pythonのイテレータプロトコルを実装しているだけです。イテレータプロトコルは Python のクラスで、 __iter__()__next__() という 2 つの特別なメソッドを持っています。この2つのメソッドにより、イテレータは反復処理の中で次の値を計算することができます。

イテレータを使えば、Pythonでアイテムの列を扱うのが簡単になります。イテレータを使えば、Pythonでアイテムのシーケンスを扱うのが簡単になります。シーケンス内のすべてのアイテムに計算資源を割り当てる必要はなく、一度に1つのアイテムを反復処理するので、メモリ領域を節約できます。

この記事では、Pythonでイテレータを使用する方法を学びます。

Pythonのイテラブルオブジェクト

イテラブルとは、イテレータを返すことができるオブジェクトのことです。イテレート可能なオブジェクトは有限および無限のデータソースを表現することができます。イテレートは直接または間接的に __iter__()__next__() という2つのメソッドを実装します。iter__()メソッドはイテレータオブジェクトを返し、next()` メソッドはイテレート可能なオブジェクトの要素を走査するのに役立ちます。

Python のイテレート可能なオブジェクトの例としては、リスト、辞書、タプル、セットなどがあります。

イテレータの作成

Python では、オブジェクトに __iter__()__next__() メソッドを実装することで、イテレータを作成します。以下の例で考えてみましょう。

class IterationExample:
    def __iter__(self):
        self.x = 0
        return self


def __next__(self):
        y = self.x
        self.x += 1
        return y


classinstance = IterationExample()
element = iter(classinstance)


0 から N までの数字を表示する element という名前のイテレータを作成しました。まず、このクラスのインスタンスを作成し、 classinstance という名前を付けました。そして、組み込みメソッド iter() を呼び出して、パラメータとしてクラスのインスタンスの名前を渡しました。これで、イテレータオブジェクトが生成されます。

では、実際にイテレータを使って項目を反復処理する方法について説明します。

イテレータを用いた反復処理

next()` メソッドは、イテレータの要素を繰り返し処理するのに役立ちます。上の例で説明しましょう。

class IterationExample:
    def __iter__(self):
        self.x = 0
        return self


def __next__(self):
        y = self.x
        self.x += 1
        return y


classinstance = IterationExample()
element = iter(classinstance)


print(next(element))
print(next(element))
print(next(element))
print(next(element))
print(next(element))
print(next(element))
print(next(element))
print(next(element))
print(next(element))
print(next(element))


出力

0
1
2
3
4
5
6
7
8
9


上のスクリプトでは、next() メソッドを呼び出し、イテレータの要素名をパラメータとしてメソッドに渡しています。これを実行するたびに、イテレータは次の要素に移動します。もうひとつの例を示します。

# create a list
list1 = [0, 5, 10, 15]


# create an iterator
element = iter(list1)


## use next() to traverse/iterate through the list elements


# prints first element, 0
print(next(element))


# prints second element, 5
print(next(element))


## next(element) is similar to element.__next__()


# prints third element, 10
print(element.__next__())


# prints fourth element, 15
print(element.__next__())


出力

0
5
10
15


上のスクリプトでは、4つの整数を含むリスト list1 を作成した。elementという名前のイテレータが作成されました。next() メソッドにより、リストの要素を反復処理することができます。

for」ループによる反復処理

for` ループは、イテレータを返すことができる任意のオブジェクトに対して反復処理を行うのに役立ちます。たとえば

# create a list
list1 = [0, 5, 10, 15]


# create an iterator
element = iter(list1)


# iterate with a for loop
for x in element:
    print(x)


出力

0
5
10
15


上のコードでは、x という名前の変数を作成し、それを使って for ループでイテレータ element を反復処理する。

無限のイテレータ

無限イテレータとは、反復回数が無限のイテレータのことです。無限イテレータを扱うときは、特に注意しなければなりません。次のような例を考えてみよう。

class IterationExample:
    def __iter__(self):
        self.x = 0
        return self


def __next__(self):
        y = self.x
        self.x += 1
        return y


classinstance = IterationExample()
element = iter(classinstance)


for x in element:
    print(x)


上のコードは永久に実行される。これを止めるには、手動で介入する必要がある。Pythonで無限イテレータを作成する方法を示す別の例を示します。

class Infinite:
    # Print all even numbers


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


def __next__(self):
        x = self.x
        self.x += 2
        return x


このコードは0から始まるすべての偶数を返すはずです。以下のようにコードを実行できます。

>>> y = iter(Infinite())
>>> next(y)
0
>>> next(y)
2
>>> next(y)
4
>>> next(y)
6
>>> next(y)
8
>>> next(y)
10
>>>


そして、この連鎖は永遠に続くのです。これは、無限イテレータを使えば、すべての項目をメモリに格納することなく、無限の数を持つことができることを示しています。

次節では、このような無限イテレータから抜け出すための機構をどのように実装すればよいかを見ていきます。

イテレーションの停止

前節では、Pythonで無限イテレータを作成する方法を見ました。しかし、Pythonではイテレータは通常、無限反復のためにあるのではありません。終了条件を実装しておくと常に便利です。

StopIterationステートメントを使えば、イテレータが永遠に実行されるのを止めることができます。あとは、next()` メソッドに終了条件を追加すれば、指定した反復回数に達したときにエラーを発生させることができます。以下はその例です。

class StoppingIteration:
    def __iter__(self):
        self.x = 1
        return self


def __next__(self):
        if self.x <= 5:
            y = self.x
            self.x += 1
            return y
        else:
            raise StopIteration


classinstance = StoppingIteration()
element = iter(classinstance)


for a in element:
    print(a)


出力

1
2
3
4
5


実行は5回繰り返したところで止まっています。これは、__next__()メソッド内に self.x <= 5: という条件を追加しているためです。5 に達した後にイテレータを呼び出すと、 StopIteration イベントが発生します。以下の例で考えてみましょう。

class StoppingIteration:
    def __init__(self, max = 0):
        self.max = max


def __iter__(self):
        self.x = 1
        return self


def __next__(self):
        if self.x <= self.max:
            val = 3 ** self.x
            self.x += 1
            return val
        else:
            raise StopIteration


イテレータを作成し、それを繰り返し処理します。

>>> y = StoppingIteration(3)
>>> z = iter(y)
>>> next(z)
3
>>> next(z)
9
>>> next(z)
27
>>> next(z)
Traceback (most recent call last):
  File "<pyshell#5", line 1, in <module
    next(z)
  File "C:Usersdminiteration.py", line 17, in __next__
    raise StopIteration
StopIteration
&gt;&gt;&gt;


この終了条件は、次のセクションで実装されています。

if self.x &lt;= self.max:
    val = 3 ** self.x


イテレータに3という値を渡しましたが、これはイテレータが27、つまり3^3を越えて反復してはいけないという意味です。

結論

イテレータは、特に大量のアイテムのシーケンスを反復処理する必要がある場合に非常に便利です。イテレータを使用すると、一度にすべての項目をメモリにロードすることなく、一連の項目を一度に反復処理することができます。

この記事では、Pythonでイテレータを作成する方法と、イテレータ内の項目を反復処理する方法について説明しました。また、無限イテレータの作成方法と、無限イテレータに終了条件を追加する方法について説明しました。

#5>をご覧ください。

タイトルとURLをコピーしました