__next__
__next__(self) any · Added in v3.9 · Updated March 18, 2026 · Keywords __next__ is the method that makes an object an iterator. While __iter__ returns the iterator object itself, __next__ returns each successive item and raises StopIteration when exhausted.
Signature
def __next__(self):
# Returns the next item in the sequence
Quick Example
class Counter:
def __init__(self, limit):
self.current = 0
self.limit = limit
def __iter__(self):
return self
def __next__(self):
if self.current >= self.limit:
raise StopIteration
self.current += 1
return self.current - 1
# Usage
for i in Counter(3):
print(i)
# Output: 0
# Output: 1
# Output: 2
How It Works
The iteration protocol involves two methods:
__iter__— Returns the iterator object. Must returnselffor the object to be its own iterator.__next__— Returns the next item. When no items remain, raiseStopIteration.
Python’s for loops and next() built-in call __next__ automatically:
counter = Counter(3)
print(next(counter)) # Output: 0
print(next(counter)) # Output: 1
print(next(counter)) # Output: 2
print(next(counter)) # Raises StopIteration
Common Patterns
Stateful Iterators
Track internal state between calls:
class Fibonacci:
def __init__(self, max_terms=10):
self.a, self.b = 0, 1
self.remaining = max_terms
def __iter__(self):
return self
def __next__(self):
if self.remaining <= 0:
raise StopIteration
self.remaining -= 1
result = self.a
self.a, self.b = self.b, self.a + self.b
return result
# Usage
fib = Fibonacci(5)
print(list(fib)) # Output: [0, 1, 1, 2, 3]
One-Shot vs Reusable
Iterators are consumed after one pass. If you need to reuse, return a fresh iterator from __iter__:
class ReusableRange:
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __iter__(self):
return RangeIterator(self.start, self.stop)
class RangeIterator:
def __init__(self, start, stop):
self.current = start
self.stop = stop
def __next__(self):
if self.current >= self.stop:
raise StopIteration
self.current += 1
return self.current - 1
# Usage
r = ReusableRange(0, 3)
print(list(r)) # Output: [0, 1, 2]
print(list(r)) # Output: [0, 1, 2] — works again!
Gotchas
Forgetting to Raise StopIteration
Always raise StopIteration when iteration ends. Otherwise, for loops may behave unexpectedly:
# Wrong — may cause infinite loop in some contexts
def __next__(self):
if self.index >= len(self.items):
return None # Don't do this
return self.items[self.index]
PEP 479: StopIteration in Generators
Since Python 3.7, StopIteration raised inside a generator is converted to RuntimeError. This prevents silent infinite loops:
def bad_generator():
value = 0
while True:
yield value
value += 1
if value > 3:
raise StopIteration # Becomes RuntimeError in Python 3.7+
Use return instead to exit generators:
def good_generator(limit):
for i in range(limit):
yield i
# Or use `return` directly:
def good_generator(limit):
value = 0
while value < limit:
yield value
value += 1
return # Clean exit
Modifying During Iteration
Modifying a collection while iterating over it can cause unexpected behavior. Use iterators to isolate the iteration state:
items = [1, 2, 3]
for item in items: # Iterates over a snapshot
if item == 2:
items.append(4) # Safe — doesn't affect current iteration
See Also
- built-in::iter — returns an iterator object
- built-in::next — retrieves the next item from an iterator
- dunder::__str__ — returns the string representation (also an iterator entry point)