StopIteration is the exception an exhausted iterator raises to signal that no values remain. A for loop catches this signal and exits instead of requiring an index. section 11.1 section 11.2
Use StopIteration as the termination part of Python’s iterator protocol:
- Implement __iter__ to return an iterator, then let repeated __next__ calls produce values. section 11.2
- Raise StopIteration when the iterator has reached the end; the surrounding for loop then exits. section 11.3
- Track iteration state on the object, such as self.index, because __next__ must preserve progress between calls. section 11.7
- Do not explicitly raise StopIteration inside a generator; reaching the function’s end raises it automatically, while return exits the generator. section 11.17
A custom iterator reaches the end
class LoudIterator: def __init__(self, data): self.data = data self.index = 0 def __iter__(self): return self def __next__(self): if self.index >= len(self.data): raise StopIteration value = self.data[self.index] self.index += 1 return value for item in LoudIterator('abc'): print(item) The loop prints a, b, and c, then stops when __next__ raises StopIteration. section 11.3
class LoudIterator():
def __init__(self, data):
print('\tNow in __init__')
self.data = data #1
self.index = 0 #2
def __iter__(self):
print('\tNow in __iter__')
return self #3
def __next__(self):
print('\tNow in __next__')
if self.index >= len(self.data): #4
print(
f'\tself.index ({self.index}) is too big; exiting')
raise StopIteration
value = self.data[self.index] #5
self.index += 1 #6
print('\tGot value {value}, incremented index to {self.index}')
return value
for one_item in LoudIterator('abc'):
print(one_item)
Trace __init__, __iter__, repeated __next__ calls, state changes, and the final StopIteration signal. section 11.3

