What is a Generator in Python?
Learn what a Python generator is, how yield pauses execution, lazy evaluation benefits, generator expressions, and the iterator protocol with examples.
Expected Interview Answer
A generator is a special kind of function that returns an iterator producing values lazily, one at a time, using the yield keyword instead of return, so it never builds the entire sequence in memory at once and can even represent infinite sequences.
When a generator function is called, it does not run its body immediately; it returns a generator object, and code only executes up to the next yield each time you call next() on it (or iterate with a for loop), pausing there with its local state preserved until resumed. This makes generators ideal for large or infinite data streams, file processing, and pipelines, because memory use stays constant regardless of how many items the sequence produces. Generator expressions, written as (x for x in iterable), give the same lazy behavior in a compact expression form, similar to a list comprehension but with parentheses instead of brackets. Generators also implement the iterator protocol automatically, so they work with for loops, sum(), list(), and any code expecting an iterable, and you can send values back into a generator with .send() for coroutine-style patterns.
- Constant memory use regardless of sequence size (lazy evaluation)
- Can represent infinite or unbounded sequences
- Simplifies building data pipelines and streaming processing
- Automatically implements the iterator protocol
- Generator expressions give a compact, list-comprehension-like syntax
AI Mentor Explanation
A generator is like a bowler who delivers one ball at a time only when the umpire signals ready, rather than bowling an entire over's worth of deliveries into a bucket beforehand. The bowler pauses between balls holding their run-up state, and the next delivery only happens when you call for it, so no overs are wasted if play is stopped early.
Step-by-Step Explanation
Step 1
yield instead of return
A generator function uses yield to produce a value and pause, instead of return which ends execution.
Step 2
Lazy call semantics
Calling the function returns a generator object immediately; no code runs until you iterate or call next().
Step 3
Paused state preserved
Between yields, all local variables and execution position are preserved automatically.
Step 4
Iterator protocol
Generators automatically support __iter__ and __next__, so they work in for loops and with sum(), list(), etc.
Step 5
Generator expressions
(x for x in iterable) gives the same lazy behavior as a compact expression, unlike a list comprehension's brackets.
Step 6
StopIteration
When the function body finishes without another yield, the generator raises StopIteration to signal it is exhausted.
What Interviewer Expects
- Explains yield as pausing execution and preserving state, unlike return
- Knows generators are lazy — nothing runs until iterated
- Understands the memory benefit over building a full list upfront
- Can distinguish a generator expression (x for x in ...) from a list comprehension
- Knows generators implement the iterator protocol automatically
Common Mistakes
- Thinking a generator function runs its body when called, before iteration starts
- Trying to re-iterate an exhausted generator and expecting it to reset
- Confusing yield with return, assuming the function ends at the first yield
- Building a full list just to iterate once, missing an obvious generator use case
Best Answer (HR Friendly)
“A generator is a memory-efficient way to produce a sequence of values one at a time, only when needed, instead of building the whole sequence in memory upfront. This makes it ideal for working with very large or even infinite data streams without running out of memory.”
Code Example
def count_up_to(n):
i = 1
while i <= n:
yield i # pause here, remember i
i += 1
gen = count_up_to(3)
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
for value in count_up_to(1_000_000):
if value > 3:
break
print(value) # 1 2 3 - never builds a million-item listFollow-up Questions
- How does a generator expression differ from a list comprehension?
- What happens when you call next() on an exhausted generator?
- How would you use a generator to process a huge file line by line?
- What is the difference between yield and yield from?
- How does .send() let you pass values back into a generator?
MCQ Practice
1. What keyword defines a generator function?
The yield keyword marks a function as a generator, pausing execution and producing a value each time it's reached.
2. When you call a generator function, what happens immediately?
Calling a generator function returns a generator object without executing any code; execution starts on the first next() call.
3. What exception signals a generator is exhausted?
When a generator's body finishes without hitting another yield, it raises StopIteration to signal completion.
Flash Cards
What keyword makes a function a generator? — yield
When does a generator function's body start executing? — Only when you call next() or start iterating, not when the function is called.
Main memory benefit of a generator? — It produces values lazily, one at a time, instead of holding the full sequence in memory.
Syntax for a generator expression? — (x for x in iterable) — parentheses instead of a list comprehension's brackets.