StopIteration は、イテレータが終端に達したことを示す例外です。普段は for 文が自動的に処理してくれるため意識することは少ないですが、イテレータを手動で操作する際には重要な概念です。
StopIteration とは
イテレータの next() を呼び出し続けると、要素がなくなった時点で StopIteration 例外が発生します。
numbers = [1, 2] it = iter(numbers) print(next(it)) # 1 print(next(it)) # 2 print(next(it)) # StopIteration 例外!
実行すると以下のようなエラーメッセージが表示されます。
Traceback (most recent call last): File "...", line 5, in <module> print(next(it)) StopIteration
for 文と StopIteration
for 文は内部で StopIteration をキャッチしてループを終了します。だから普段は意識する必要がありません。
# この for 文は... for n in [1, 2, 3]: print(n) # 内部的にはこう動いている it = iter([1, 2, 3]) while True: try: n = next(it) print(n) except StopIteration: break
手動で StopIteration を扱う
next() のデフォルト値を使わない場合は、try-except で捕捉します。
numbers = [1, 2] it = iter(numbers) while True: try: n = next(it) print(n) except StopIteration: print("イテレータが終了しました") break
ジェネレータと StopIteration
ジェネレータ関数が終了すると、自動的に StopIteration が発生します。
def count_up_to(n): i = 1 while i <= n: yield i i += 1 # 関数終了時に StopIteration が自動発生 gen = count_up_to(2) print(next(gen)) # 1 print(next(gen)) # 2 print(next(gen)) # StopIteration
StopIteration に値を持たせる
StopIteration は値を持つことができます。ジェネレータで return を使うと、その値が StopIteration の value 属性に格納されます。
def gen_with_return(): yield 1 yield 2 return "完了" g = gen_with_return() print(next(g)) # 1 print(next(g)) # 2 try: next(g) except StopIteration as e: print(e.value) # 完了
この仕組みは、コルーチンや yield from と組み合わせて使われることがあります。