Python Docs
Iterators
The Python iterator protocol consists of two methods: __iter__(), which returns the iterator object itself, and __next__(), which returns the next item or raises StopIteration when there are no more items.
Built-in Iterators
Most built-in containers like list, tuple, dict and set return an iterator when you call iter() on them.
it = iter([1, 2, 3]) print(next(it)) # 1 print(next(it)) # 2 print(next(it)) # 3 # next(it) -> StopIteration
Custom Iterator Class
You can implement your own iterator by defining __iter__ and __next__. __iter__ should return the iterator object (usually self).
class CountDown:
def __init__(self, start):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current < 0:
raise StopIteration
value = self.current
self.current -= 1
return value
for x in CountDown(3):
print(x) # 3, 2, 1, 0Iterables vs Iterators
- Iterable: Has
__iter__()that returns a new iterator each time (e.g. lists, ranges). - Iterator: Implements both
__iter__()and__next__()and is usually one-shot. - One-shot: Once consumed, an iterator is typically exhausted and cannot be reused.
nums = [1, 2, 3] it1 = iter(nums) it2 = iter(nums) # new, independent iterator print(next(it1)) # 1 print(next(it2)) # 1 (separate state)
Tools: itertools
The itertools module provides building blocks for creating fast, memory-efficient iterator pipelines.
import itertools as it
data = [1, 2, 3, 4, 5]
print(list(it.accumulate(data))) # Running totals
print(list(it.compress("ABCDE", [1, 0, 1, 0, 1]))) # A C E
print(list(it.islice(range(10), 2, 8, 2))) # 2 4 6Best Practices
- Prefer generators for custom iteration logic — they're simpler than writing full iterator classes.
- Do not assume an iterator can be reused; create a fresh iterator when you need to iterate again.
- Let
forloops handleStopIterationimplicitly instead of callingnext()manually.