クラス

【Python】イテレータ(iterator)の基本

【Python】イテレータ(iterator)の基本

Pythonにおけるイテレータ(iterator)の基本について解説します。

イテレータ(iterator)

イテレータ(iterator)とは

イテレータ(iterator)とは、繰り返しに必要な特殊メソッドを実装したコンテナオブジェクトの事を言います。ここで言っている特殊メソッドとは具体的に、イテレータプロトコルを実現する以下の2つのメソッドです。

メソッド名概要
__next__()コンテナの次の要素を返す
__iter__()イテレータ自身を返す

Pythonを学んでいるとイテラブル(iterable)という言葉を聞くことがあるかと思います。イテラブルとは、for文で要素として1つずつ取り出せるような反復可能なオブジェクトのことで、代表的なものとしてリスト(list)、タプル(tuple)、辞書(dict)等があります。__iter__()メソッドかもしくは__getitem__()メソッドを持つ任意のクラスのオブジェクトもイテラブルです。イテラブル(iterable)に関する公式ドキュメントの説明はこちらを参照してください。

イテレータは、イテラブルなオブジェクトのことで、繰り返しの状態を保持しておき、順番に要素を1つずつ取りだすことができます。

組み込み関数のiter()に以下の例のようにシーケンス(文字列等)を渡すとイテレータを作成することができます。1つずつ値を取り出せることを見てみましょう。

sample = "python"

# イテレータを作成
i = iter(sample)
print(type(i))

# 値を順に取り出す
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
# 全て取り出し終わるとStopIteration例外となる
print(next(i))
【実行結果】
<class 'str_ascii_iterator'>
p
y
t
h
o
n
Traceback (most recent call last):
...(省略)...
StopIteration

上記のようにiter関数に文字列を渡すと’str_ascii_iterator’というイテレータが作成されます。

イテレータは、next関数に渡すと順に値を取り出すことができ、上記の例では”p”, “y”, “t”, “h”, “o”, “n”と順に文字列の値が取り出されていることが分かります。

値を全て取り出し終わると、イテレータはStopItaration例外を送出します。for文ではこのStopItaration例外をとらえるとループが終了するようになっているので、イテレータはfor文で使用することができます。

独自のカスタムイテレータ(iterator)の作成

イテレータ(iterator)は、特殊メソッドの__next__()メソッドと__iter__()メソッドを実装したコンテナオブジェクトでした。これらのメソッドを自分で実装することで、独自のカスタムイテレータを作成することができます。

例えば、数値をカウントダウンするMyCountDownクラスという簡単なクラスを作ってみましょう。

class MyCountDown:
    """カウントダウンイテレータ"""

    def __init__(self, count):
        self.count = count

    def __next__(self):
        """次の値を返す"""
        # 繰り返しの終わりではStopIteration例外を送出する
        if self.count <= 0:
            raise StopIteration
        # カウントダウン
        self.count -= 1
        # 次の値を返す
        return self.count

    def __iter__(self):
        """イテレータの状態を返す"""
        # イテレータ自身を返却
        return self


def main():
    count_iter = MyCountDown(5)
    for c in count_iter:
        print(c)


if __name__ == "__main__":
    main()
【実行結果】
4
3
2
1
0

上記のMyCountDownクラスの__next__()メソッドでは、countを1減らして値を返却します。もしマイナスの値になった際にはStopIteration例外を送出(raise)するようになっています。また、__iter__()メソッドでは、イテレータ自身のselfを返却しています。

main関数内でMyCountDownクラスのオブジェクトを作成し、for文で使用しながら値を出力しています。値のカウントダウンができ、終了時にはfor文を抜けていることが分かります。

このように__next__()メソッドや__iter__()メソッドを自分で作成することで独自のカスタムイテレータを作成することが可能です。

itertools ~効率的なループ実行のためのイテレータ生成関数~

Pythonのライブラリにイテレータの使い方としてよくあるパターンを実装したitertoolsと呼ばれるライブラリがあります。itertoolsを使うことでイテレータを簡単に活用することが可能です。

for文でよく使われるzipの説明をしている「zipを用いたfor文の使い方 ~複数のリストをまとめて処理~」のページでも、実はitertoolsのzip_longestを紹介しています。通常のzipが要素の少ない方にあわせて処理をするのに対して、itertoolsのzip_longestは要素数が多い方にあわせて足りない部分を補完して処理したい場合に使われます。

itertoolsには、他にも実装されているものがあるので、また整理してみようかなと思います。

Note

itertoolsの公式ドキュメントはこちらを参照してください。

まとめ

Pythonにおけるイテレータ(iterator)の基本について解説しました。

イテレータ(iterator)とは、繰り返しに必要な特殊メソッドを実装したイテラブル(iterable)なコンテナオブジェクトの事を言います。

イテレータは順番に要素を1つずつ取り出すことができfor文で利用することができます。また、イテレータは__next__()メソッドや__iter__()メソッドを自分で実装することで独自のカスタムイテレータを作成することも紹介しました。

イテレータをあえて使用しなくてもプログラム開発ができるわけですが、イテレータはジェネレータの基礎にもなっていますので、考え方を理解してもらえるとよいかなと思います。ジェネレータについては「ジェネレータ(generator)関数 ~yieldによる返却~」でも紹介していますので興味があれば参考にしてください。