イテレータは、複数個の要素を保持しているオブジェクトから、要素を一つずつ順に取り出すためのインタフェースである。複数個の要素を保持している型として、リスト、ディクショナリ、タプル、集合などがある。これらのオブジェクト(例えば、リスト)に対して、for 構文を適用すると、リスト中の各要素を順に取り出すことができる。これは、リストがイテレータとしての機能が実装されているために、for 構文による要素の取り出しが可能になるからである。
for 構文を利用せずに、イテレータの基本的な制御方法でリストの要素を取り出す例を次に示す。はじめに、リストを iter
関数に代入し、リストをイテレータとして制御できるような形に変換する。次に、next
関数を使って、リスト中の最初の要素を取り出す。その後、next
をもう一度使って、2 番目の要素を取り出す。このように、iter
関数でリストをイテレータに変換すると、next
関数を必要な回数だけ実行して、要素を 1 つずつ順に取り出すことができるようになる。そして、最後の要素に達したあとに、next
関数を実行すると、StopIteration
例外が発生する。
a = [1, 2, 3, 4, 5]
a_iter = iter(a)
next(a_iter)
# 1
next(a_iter)
# 2
next(a_iter)
# 3
next(a_iter)
# 4
next(a_iter)
# 5
next(a_iter)
# StopIteration
リストに対して for 構文を適用すると、リストの中から要素を 1 つずつ順に取り出すことができる。これは、for 構文を使用したときに、自動的に iter
関数が呼び出されて、その後、next
関数を繰り返して実行して、StopIteration
となったら for 構文から抜ける、という制御が書かれていると考えても良い。
イテレータを自作することができる。イテレータをクラスとして定義し、クラスの中で __iter__
および __next__
メソッドを定義する。iter
関数を使用したときに __iter__
が実行され、next
関数を使用したときに __next__
が実行される。次は、5 つの値を受け取り、それらをイテレータとして使えるような形で変換している例である。
class Arr:
def __init__(self, a, b, c, d, e):
self.x = [a, b, c, d, e]
self.i = 0
def __iter__(self):
return self
def __next__(self):
if self.i == len(self.x):
raise StopIteration()
ret = self.x[self.i]
self.i = self.i + 1
return ret
a = Arr(1, 2, 3, 4, 5)
for i in a:
print(i)
# 1
# 2
# 3
# 4
# 5
もう一つの例を示す。与えられたリストの中から、奇数番目の要素を取り出すイテレータの例である。
class EvenList:
def __init__(self, arr):
self.x = arr
self.i = 0
def __iter__(self):
return self
def __next__(self):
current_i = self.i
# i に 2 を足して、次の奇数番目要素のインデックスを取得する
self.i = self.i + 2
if current_i == len(self.x):
raise StopIteration()
return self.x[current_i]
a = EvenList([1, 2, 3, 4, 5, 6, 7, 8])
for i in a:
print(i)
# 1
# 3
# 5
# 7