Module 13 β Generators
Producing values one at a time, on demand, instead of all at once.
Prerequisite: Module 12 β Closures & Decorators
After this lesson, you will be able to
- Write a generator function using yield
- Explain lazy evaluation and why it saves memory
- Write a generator comprehension
Concept & Syntax
A normal function computes its entire result and returns it all at once. A generator
function instead uses yield to hand back one value at a time, pausing itself exactly where it left
off, and only resuming when the next value is asked for. This is called lazy evaluation.
The payoff is memory. A list of one million numbers takes up space for all one million, all the time. A generator that yields one million numbers only ever holds one number in memory at any moment β hugely useful when working with large or even infinite sequences.
def count_up_to(n):
i = 1
while i <= n:
yield i
i += 1
for number in count_up_to(5):
print(number)Examples
A simple generator function Very Easy
def count_up_to(n):
i = 1
while i <= n:
yield i
i += 1
for number in count_up_to(5):
print(number)Each time the loop asks for the next value, the function resumes right after its last yield, runs a bit more, then pauses again.
Calling next() manually Intermediate
def two_numbers():
yield 10
yield 20
gen = two_numbers()
print(next(gen))
print(next(gen))next() pulls the next yielded value out of the generator. Calling it a third time here would raise StopIteration.
Generator comprehension Real World
squares = (x * x for x in range(1000000))
print(next(squares))
print(next(squares))Parentheses (instead of square brackets) create a generator comprehension β a million squares are never all stored in memory at once, only computed as needed.
Visual Explanation
π‘ Why does this work?
Read the concept explanation above again slowly, line by line β every keyword there maps directly onto a line of code in the examples. If it still doesn't click, re-run the traced example (if this lesson has one) one step at a time.
π What happens internally? (advanced)
Under the hood, Python compiles your source into bytecode and runs it on a virtual machine (the CPython interpreter). Variables are names in a namespace dictionary pointing at objects in memory β which is exactly what the memory panel in the tracer above is showing you.
Common Mistakes
A function containing yield never runs its body immediately when called β calling it just creates a generator object.
def numbers():
yield 1
yield 2
print(numbers())def numbers():
yield 1
yield 2
for n in numbers():
print(n)- Use a generator instead of building a full list whenever you only need to iterate once, especially over large data.
- Prefer a generator comprehension (x for x in ...) over a list comprehension when you don't need random access or len().
- Remember a generator can only be iterated through once β once exhausted, you must create a new one.
Exercise & Challenge
Exercise 1 β Predict the output
def letters():
yield "a"
yield "b"
g = letters()
next(g)
print(next(g))What does this print?
π Challenge
Write a generator function even_numbers(limit) that yields even numbers from 0 up to (not including) limit, then use it in a for loop to print them.
- Use yield, not return
- Only yield even numbers
- Stop before reaching limit
π‘ Need a hint?
A while loop with i += 2 naturally produces only even numbers if it starts at 0.
π Show a sample solution
def even_numbers(limit):
i = 0
while i < limit:
yield i
i += 2
for n in even_numbers(10):
print(n)Quiz
Answer every question, then submit to see your score and explanations.
1. What keyword turns a regular function into a generator function?
2. What happens when you call a generator function?
3. Why are generators more memory-efficient than building a full list?
Summary
- yield turns a function into a generator that produces values one at a time.
- Calling a generator function doesn't run its body β only next() (or a for loop) does.
- Generators use lazy evaluation, making them far more memory-efficient than full lists for large sequences.
- A generator can only be consumed once.