Python のイテレータ (Iterators)
1. Python イテレータ
イテレータ(Iterator)は、数えられる数の値を含むオブジェクトです。
イテレータは、すべての値を反復(イテレート)できるオブジェクト、つまり、その上を走査できるオブジェクトを指します。
技術的な定義では、Python におけるイテレータとは、イテレータプロトコル(Iterator Protocol)を実装したオブジェクトであり、__iter__() と __next__() というメソッドで構成されています。
2. イテレータ vs イテラブル
リスト(List)、タプル(Tuple)、辞書(Dictionary)、セット(Set)はすべてイテラブル(Iterable)なオブジェクトです。これらは、そこからイテレータを取得できる「イテラブルな容器」のような存在です。
これらのオブジェクトはすべて、イテレータを取得するために使用される iter() メソッドを持っています。
2.1 タプルからのイテレータ取得
タプルからイテレータを取得し、各値を順次出力する例です。
mytuple = ("リンゴ", "バナナ", "チェリー")
myit = iter(mytuple)
print(next(myit)) # リンゴ
print(next(myit)) # バナナ
print(next(myit)) # チェリー2.2 文字列のイテレーション
文字列(String)もイテラブルなオブジェクトであり、一連の文字で構成されています。そのため、文字列からもイテレータを取得することが可能です。
mystr = "バナナ"
myit = iter(mystr)
print(next(myit))
print(next(myit))
print(next(myit))3. イテレータのループ処理
for ループを使用することで、イテラブルなオブジェクトを効率的に走査できます。
3.1 リストの走査
mylist = ["リンゴ", "バナナ", "チェリー"]
for x in mylist:
print(x)3.2 タプルの走査
mytuple = ("リンゴ", "バナナ", "チェリー")
for x in mytuple:
print(x)実際には、for ループは背後でイテレータオブジェクトを作成し、各ループごとに next() メソッドを実行しています。
4. カスタムイテレータの作成
独自のクラスをイテレータとして定義するには、__iter__() と __next__() メソッドをそのクラスに実装する必要があります。
Python のクラス設計において、すべてのクラスには __init__() という初期化メソッドがありますが、イテレータの実装には以下のメソッドが重要になります。
__iter__():__init__()と同様に初期化処理を行えますが、最終的にイテレータオブジェクト自体(通常は self)を返す必要があります。__next__(): 次のアイテムを返すための操作を記述します。
4.1 数値を生成するイテレータの実装
1 から始まり、呼び出されるたびに数値を 1 ずつ増加させるイテレータの例です。
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
myclass = MyNumbers()
myiter = iter(myclass)
print(next(myiter)) # 1
print(next(myiter)) # 2
print(next(myiter)) # 3
print(next(myiter)) # 4
print(next(myiter)) # 55. StopIteration による終了制御
上記の例では、next() を呼び出し続ければ数値は無限に増え続けます。
特に for ループで利用する場合、適切なタイミングで反復を終了させるために StopIteration ステートメントを使用します。
__next__() メソッド内で条件判定を行い、指定した回数に達した際にエラーを発生させることで、ループを安全に停止させることができます。
5.1 20回で停止するイテレータの実装
20回繰り返した後に自動で停止する設定を加えた例です。
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
if self.a <= 20:
x = self.a
self.a += 1
return x
else:
# 反復を終了させる例外を発生させる
raise StopIteration
myclass = MyNumbers()
myiter = iter(myclass)
for x in myiter:
print(x)