Complete guide to Python's __next__ method covering iterators, iteration protocol, generators, and custom iteration.
Last modified April 8, 2025
This comprehensive guide explores Python’s next method, the special method that powers iteration in Python. We’ll cover the iteration protocol, custom iterators, generators, and practical examples.
The next method is part of Python’s iterator protocol. It returns the next item from an iterator. When no more items are available, it raises StopIteration.
Key characteristics: it takes no arguments (except self), returns the next value in sequence, and maintains internal state between calls. It works with iter to implement the full iteration protocol.
Here’s a simple iterator class implementing both iter and next methods. This demonstrates the fundamental iterator pattern.
basic_iterator.py
class CountUpTo: def init(self, max): self.max = max self.current = 0
def __iter__(self):
return self
def __next__(self):
if self.current >= self.max:
raise StopIteration
self.current += 1
return self.current - 1
counter = CountUpTo(5) for num in counter: print(num) # Prints 0 1 2 3 4
This iterator counts from 0 up to (but not including) the specified maximum. The next method increments the counter and returns values until reaching the limit.
The iter method returns self, making the object both an iterator and iterable. This is common for simple iterators.
Iterators don’t have to be finite. This example shows an infinite iterator that generates Fibonacci numbers indefinitely.
infinite_iterator.py
class Fibonacci: def init(self): self.a, self.b = 0, 1
def __iter__(self):
return self
def __next__(self):
result = self.a
self.a, self.b = self.b, self.a + self.b
return result
fib = Fibonacci() for i, num in enumerate(fib): print(num) if i >= 9: # Print first 10 numbers break
This Fibonacci iterator never raises StopIteration, making it infinite. We control iteration externally with a break condition.
The state (current Fibonacci numbers) is maintained in instance variables between next calls. This demonstrates stateful iteration.
This practical example creates an iterator that reads lines from a file lazily, which is memory-efficient for large files.
file_iterator.py
class FileLineIterator: def init(self, filename): self.file = open(filename)
def __iter__(self):
return self
def __next__(self):
line = self.file.readline()
if not line:
self.file.close()
raise StopIteration
return line.strip()
def __del__(self):
if hasattr(self, 'file') and self.file:
self.file.close()
lines = FileLineIterator(‘data.txt’) for line in lines: print(line)
This iterator reads one line at a time from the file, only loading what’s needed into memory. It properly closes the file when iteration completes.
The del method ensures the file is closed if the iterator is garbage collected before completion. This is important for resource cleanup.
This example demonstrates how to chain multiple iterators together using next, creating a single continuous sequence.
chain_iterators.py
class ChainIterators: def init(self, *iterables): self.iterables = iter(iterables) self.current = iter(next(self.iterables))
def __iter__(self):
return self
def __next__(self):
try:
return next(self.current)
except StopIteration:
self.current = iter(next(self.iterables))
return next(self.current)
chained = ChainIterators([1, 2, 3], ‘abc’, (4.5, 6.7)) for item in chained: print(item) # Prints 1, 2, 3, ‘a’, ‘b’, ‘c’, 4.5, 6.7
This iterator chains multiple sequences together, seamlessly transitioning from one to the next when each is exhausted. It handles any iterable input.
The implementation uses nested iterators, catching StopIteration from the current iterator to move to the next one in sequence.
This advanced example shows an iterator that can be reset to its initial state, demonstrating more complex next behavior.
resettable_iterator.py
class ResettableRange: def init(self, start, stop): self.start = start self.stop = stop self.reset()
def reset(self):
self.current = self.start
def __iter__(self):
return self
def __next__(self):
if self.current >= self.stop:
raise StopIteration
result = self.current
self.current += 1
return result
ranger = ResettableRange(2, 5) print(list(ranger)) # [2, 3, 4] ranger.reset() print(list(ranger)) # [2, 3, 4] again
This iterator mimics range behavior but adds a reset method to restart iteration from the beginning. The state is maintained but can be reset on demand.
The reset method demonstrates how to manage iterator state externally, providing more control over iteration behavior.
Always raise StopIteration: When no more items are available
Maintain state carefully: Ensure consistent behavior between calls
Implement iter: Make your iterator properly iterable
Consider memory usage: Iterators should be memory-efficient
Document behavior: Clearly document iteration behavior and limits
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Python tutorials.