What Are Iterators in Python and How Do They Work?
Learn how Python iterators work, the difference between iterables and iterators, the StopIteration signal, and how generators simplify building custom ones.
Expected Interview Answer
An iterator is an object that implements `__iter__` (returning itself) and `__next__` (returning the next value or raising StopIteration), enabling one-at-a-time traversal of a sequence without loading it all into memory.
An iterable is anything with `__iter__` that produces an iterator, such as a list, but the iterator itself is a separate, stateful object tracking position via `__next__`. `for` loops call `iter()` on the iterable to get an iterator, then repeatedly call `next()` until StopIteration is raised, at which point the loop ends automatically. Generators, created with `yield` or generator expressions, are the most common way to build iterators without writing a full class, and they're memory-efficient because values are produced lazily on demand rather than stored all at once.
- Processes huge or infinite sequences without loading everything into memory
- Powers for loops, comprehensions, and unpacking uniformly
- Generators make writing custom iterators concise
- Supports lazy evaluation for better performance
- Enables composing pipelines of transformations, e.g. with itertools
AI Mentor Explanation
An iterator is like a scorer calling out one ball's outcome at a time from the day's play, holding a bookmark of exactly which ball comes next rather than reading out the whole innings at once. Asking for the next ball after the last one has been bowled is like the scorer declaring the innings closed — StopIteration is that closing announcement.
Step-by-Step Explanation
Step 1
Iterable vs iterator
An iterable has __iter__; calling it returns an iterator object with state.
Step 2
__next__ produces values
Each call to next() advances the iterator and returns the next value.
Step 3
StopIteration signals the end
When exhausted, __next__ raises StopIteration, which for loops catch silently.
Step 4
for loops use this protocol
for x in obj calls iter(obj) once, then next() repeatedly until StopIteration.
Step 5
Generators simplify creation
A function with yield automatically becomes a generator, implementing the iterator protocol for you.
What Interviewer Expects
- Distinguishes an iterable from an iterator precisely
- Names __iter__ and __next__ as the required protocol methods
- Explains StopIteration's role in ending iteration
- Knows generators implement this protocol implicitly via yield
- Understands the memory benefit over eagerly building a full list
Common Mistakes
- Using 'iterable' and 'iterator' interchangeably
- Forgetting an iterator is exhausted after one full pass
- Not knowing __iter__ on an iterator should return self
- Assuming a generator can be reset by calling iter() on the exhausted generator itself
Best Answer (HR Friendly)
“An iterator lets you go through a sequence of values one at a time, on demand, instead of loading everything into memory at once. This is what makes Python's for loops work, and it's especially useful for processing very large or infinite data streams efficiently.”
Code Example
class Countdown:
def __init__(self, start):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current <= 0:
raise StopIteration
self.current -= 1
return self.current + 1
for n in Countdown(3):
print(n) # 3, 2, 1
# Same behavior with a generator
def countdown(start):
while start > 0:
yield start
start -= 1
for n in countdown(3):
print(n) # 3, 2, 1Follow-up Questions
- What is the difference between an iterable and an iterator?
- How does a generator function implement the iterator protocol automatically?
- Can an iterator be iterated over more than once?
- What does itertools offer on top of basic iterators?
- How does Python's for loop use iter() and next() internally?
MCQ Practice
1. Which two methods define the iterator protocol?
An iterator must implement __iter__ (returning itself) and __next__ (returning the next value or raising StopIteration).
2. What exception signals the end of iteration?
Iterators raise StopIteration from __next__ when there are no more values to produce.
3. What is the simplest way to build a custom iterator?
A generator function using yield automatically implements the full iterator protocol without a manual class.
Flash Cards
What must an iterator implement? — __iter__ (returns self) and __next__ (returns next value or raises StopIteration).
What's the difference between iterable and iterator? — An iterable produces an iterator via __iter__; the iterator itself tracks position.
How do generators relate to iterators? — A generator (using yield) automatically implements the iterator protocol.
What happens when an iterator is exhausted? — Further next() calls raise StopIteration; it cannot be reset.