イテレータとは

6.1 イテレータとは

イテレータとは、イテレーション可能な構造を持つ(イテラブルな)オブジェクトのことです。イテレーションとは、繰り返すことで、次の要素にアクセスできることを意味するので、次の要素に順にアクセスできるものをイテレータだと思ってください。
Python入門で学んだfor文をイメージするとわかりやすいかもしれません。for文は構文の一種ですのでイテレータそのものではありませんが、イテレータの機能を使用しているからです。

6.1.1 イテレータの定義

イテレータの定義をもう少し明確にすると、自身を戻り値とする「__iter__メソッド」と、次の値を参照するための「__next__メソッド」の二つの特殊メソッドが含まれるオブジェクトを、イテレータだと定義することができます。

イテレータの要件
① 自身を戻り値とする「__iter__メソッド」が含まれている。
② 次の値を参照する「__next__メソッド」が含まれている。

6.1.2 イテレータの一般的な作成方法

では実際にイテレータの作成方法について確認していきましょう。イテレータはiter関数を使用することで、イテレータが生成されます。
リストや辞書、タプルのような反復可能な変数を引数にiter関数を使用することが一般的です。

書式:イテレータの生成

    イテレータ用の変数 = iter(変数)
	

生成したイテレータから、for文を介して値を一つずつ取り出すことができます。

凡例

    numbers = [1,2,3,4,5]
    numbers2 = iter(numbers)

    for i in numbers2:
        print(i)
	

出力結果

	1
	2
	3
	4
	5
	

また文字列や文章などstr型の変数にiter関数を使用してイテレータを生成することもでき、その場合、各文字が各要素として扱われます。

凡例

    hiragana = 'あいうえお'
    words = iter(hiragana)

    for word in words:
        print(word)
	

出力結果

	あ
	い
	う
	え
	お
	

iter関数は整数や小数などint型やfloat型の変数に使用することはできませんので気を付けてください。

6.1.3 イテレータの主な使い方

またイテレータの特徴として、next関数を使うことで次の要素を参照することができることがあげられます。この関数はイテレータに対して有効な関数であり、先ほどの「__next__メソッド」と同じ機能を持っており、イテレータ変数そのものを引数に使用する関数です。

通常、for文を介して値を取り出すと、インデックス番号が0の値から一つずつ取り出しますが、next()関数を使用すると、使用した数だけ、参照される値のインデックス番号の開始値がずれていきます。

書式:イテレータの次の値を参照

    next(イテレータ用の変数)
	

凡例

    numbers = [1,2,3,4,5]
    numbers2 = iter(numbers)
    next(numbers2)
    next(numbers2)
    for i in numbers2:
        print(i)
	

出力結果

	3
	4
	5
	

iter関数を介してリスト型変数numberの値を一つずつ格納したイテレータnumber2を作成してます。順番に1、2、3、4、5の値を含んでますが、next()関数を2回使用したため、for文を介して値を参照する際には、最初の1、2の次の3から参照尾が行われてます。

凡例のイメージを図にまとめると以下の通りです。

図 6.1.1: イテレータnext関数

6.1.4 イテレータをゼロから実装する方法

イテレータの中身を理解するために、イテレータを生成できるクラスを実装してみましょう。イテレータというオブジェクトには、「__iter__メソッド」と「__next__メソッド」の二つのメソッドが含まれているため、当然、イテレータを生成するクラスには、これらのメソッドが含まれてなければなりません。

またコンストラクタには、インスタンス変数としてリストを格納するための変数と、インデックス番号を格納するための初期値が0の変数を宣言する必要があります。

イテレータ生成のクラスを定義すると以下の書式になります。

書式:イテレータ生成のクラスを定義

上記の書式ではわかりやすくするために、インデックス番号用のインスタンス変数をindexという名前にしてます。「__next__メソッド」内で行われている内容をまとめると以下の通りになります。

__next__メソッド内の処理
① リストの数(len(self.インスタンス変数))をインデックス番号が上回った時、イテレーションを終了させるための条件分岐を設けている。
② リスト(インスタンス変数)から現インデックス番号の値が代入されたvalue(※命名は任意)を宣言している。
③ 次のインデックス番号を参照できるよう、「self.index += 1」という命令文を加えている。
④ for文を使う際に出力される値として、返り値にvalueを指定している。

6.1.5 イテレータ生成するクラスのプログラム

ではイテレータが生成されるクラスを定義したプログラムを確認していきましょう。

ソース・フォルダー: /Desktop/Python基礎講座
ファイル名: 第6章.ipynb
アクセスURL: http://localhost:8888/notebooks/Desktop/Python基礎講座/第6章.ipynb

    class Number:
        def __init__(self,numbers):
            self.numbers = numbers
            self.index = 0

        def __iter__(self):
            return self

        def __next__(self):
            if self.index >= len(self.numbers):
                raise StopIteration
            value = self.numbers[self.index]
            #次のインデックス番号を指定
            self.index += 1
            return value

    numbers = [1,2,3,4,5]
    num1 = Number(numbers)
    next(num1)

    for i in num1:
        print(i)
	

実行結果

	2
	3
	4
	5
	
解説

1~15行目でNumberクラスを定義しております。2~4行目でコンストラクタを定義してます。コンストラクタ内では、リストを格納するためのnumbersというインスタンス変数、インデックス番号を格納するためのindexというインスタンス変数を初期値0で宣言してます。

    def __init__(self,numbers):
        self.numbers = numbers
        self.index = 0
	

6、7行目でクラス自身を表す、__iter__メソッドを定義し、9~15行目で次の値を参照するための__next__メソッドを定義してます。
10行目のlen(self.numbers)はリストの長さを表しているので、最後のインデックス番号に該当します。そのため「if self.index >= len(self.numbers):」とすることで、インデックス番号が最後を迎えて場合の処理を指定することができ、if文内の処理はイテレーションを終了させえるための「raise StopIteration」となっています。

    def __next__(self):
        if self.index >= len(self.numbers):
            raise StopIteration
        value = self.numbers[self.index]
        #次のインデックス番号を指定
        self.index += 1
        return value
	

また、こちらのメソッドの処理をまとめると以下の通りです。

__next__メソッド内の処理
  • 10~11行目:リストの数(len(self. numbers))をインデックス番号(self.index)が上回った時、イテレーションを終了させるための条件分岐を設けている。
  • 12行目:リスト(self. numbers)から現インデックス番号(self.index)の値が代入されたvalue(※命名は任意)を宣言している。
  • 14行目:次のインデックス番号を参照できるよう、「self.index += 1」という命令文を加えている。
  • 15行目:or文を使う際に出力される値として、返り値にvalueを指定している。

17行目でnumbersというリスト型変数を宣言し、18行目ではこちらの変数を引数にNumberクラスから、num1というインスタンスを生成してます。

    numbers = [1,2,3,4,5]
    num1 = Number(numbers)
    next(num1)

    for i in num1:
        print(i)
	

19行目でnext(num1)となっているので、21、22行目でのfor文では、1から5までの値ではなく、1を飛ばして2から5までの値を参照しているため、このような出力結果となります。

凡例のイメージを図にまとめると以下の通りです。

図 6.1.2: イテレータ生成のクラス

ポイント

  • イテレータとは自身を戻り値とする「__iter__メソッド」と、次の値を参照するための「__next__メソッド」を含むもの
  • リストや辞書、タプルなど要素を複数持つデータ型の変数や文字列などのstr型の変数にiter関数を用いてイテレータを生成できる。
  • 文字列にiter関数を使用すると、一文字ずつが各要素として代入先の変数に格納される。
  • 整数や小数などint型やfloat型の変数にiter関数を介してイテレータは生成できない。
  • next関数を使うと次の要素が参照される。

NEXT>> 6.2 ジェネレータについて