イテレータ(Python_36)

この連載では、Pythonについて色々な形で再学習に取り組んでいます。前回の記事はこちらになります。

hirocom777.hatenadiary.org

前回は、カレンダーについて見ていきました。calendarモジュールを使ってカレンダーの表示ができます。

今回は、イテレータについてです。前回の後半でcalendarモジュールを使って、日付データのイテレータを作成できる旨ご紹介しました。「イテレータ」とは何なんでしょうか。

イテラブル

for文の説明をした記事で、以下のように説明しました。

要素を取り出す順番が決まっているオブジェクトを、イテラブルなオブジェクトといいます。以下のように記述します。

for 変数 in イテラブルなオブジェクト:
   # 処理 

ここでいう「イテラブルなオブジェクト(以下、イテラブル)」とは、「イテレータを生成できるオブジェクト」のことです。そして「イテレータ」とは、「要素を1つずつ取り出せるオブジェクト」なのです。

先のfor文の例の様にイテラブルを配置すると、自動的にイテレータが生成され、要素を1つずつ取り出して処理します。イテレータ自身もイテラブルです。よって、for文は以下の様にも書けます。

for 変数 in イテレータ:
   # 処理 

dir()関数を使用して確認すると、イテラブルには必ず特殊メソッド「iterメソッド」があります。iterメソッドを使用することで、イテレータを生成します。

イテレータにも(イテレータ自身もイテラブルなので)iterメソッドがあります。加えてイテレータには「nextメソッド」があります。nextメソッドを使用すると、イテレータの次の要素を取得できます。

for文は、これらの特殊メソッドを使用してイテレータから1つずつ要素を取り出して処理しています。

イテレータの作成

イテラブルを指定してiter()関数を使用すると、iterメソッドが呼び出されてイテレータが作成されます。イテレータを指定してnext()関数を使用すると、nextメソッドが呼び出されてイテレータの次の要素が取得できます。

以下はiter()関数とnext()関数の使用例です。

it = iter([0,1,2]) # イテラブル(リスト)からイテレータを生成

print(next(it)) # 0 を返す
print(next(it)) # 1 を返す
print(next(it)) # 2 を返す
print(next(it)) # 例外 StopIteration が発生する

リストから要素を1つずつ取得しています。最後まで取得すると、次は例外「StopIteration」が発生します。StopIterationは、イテレータの要素が最後まで取り出された場合の例外です。

リストのnextメソッド

上の例ではリストからイテレータを生成しています。でも、リスト自体にはnextメソッドが定義されていません。実は、iter()関数が実行された時(iterメソッドを呼び出したとき)、リスト専用の内部イテレータオブジェクト(リストイテレータオブジェクト)が生成されるのです。

iterメソッドは、このオブジェクト内に定義されています。

it = iter([0,1,2])

print(type(it)) # <class 'list_iterator'> を返す

イテレータを作る

クラスにiterメソッド、nextメソッドを記述すれば、独自のイテレータを作成できます。以下は作成例です。

class CountUp:
    def __init__(self, max_value):
        # カウント最大値を設定
        self.max_value = max_value

    def __iter__(self):
        # カウントを初期化してイテレータを生成
        self.current = 1
        return self

    def __next__(self):
        if self.current <= self.max_value:
            # 現在の値を返してカウントアップ
            result = self.current
            self.current += 1
            return result
        else:
            # 最大値を超えたらStopIteration例外を発生させる
            raise StopIteration

# イテレータの作成
my_iterable = CountUp(5)

# forループで使用できる
for value in my_iterable:
    print(value , end = " ") # 1 2 3 4 5 を返す

御覧の通り、イテレータとして動作していることがわかります。「raise StopIteration」は、例外「StopIteration」を発生させます。

次回はジェネレーター

いかがでしょうか。イテラブル、イテレータの仕組みがわかってきました。ところで、似たような仕組みに「ジェネレーター」なるものがあります。次回はこちらを取り上げようと思います。お楽しみに!!

hirocom777.hatenadiary.org

Python再学習のまとめはこちら!!