Python Generators Practice Guide: Lazy Values
Generators are less about a new syntax trick and more about a different execution model: produce a value, pause, and resume later. That model is useful when a full list would be wasteful, impossible, or simply unnecessary.
Start with a function that yields
A generator function looks like a normal function until it reaches yield. At that point it returns one value and remembers its local state. The next request continues on the following line. Use a for loop when you want every value, and next when you want one at a time.
def countdown(n):
while n > 0:
yield n
n -= 1
for value in countdown(3):
print(value)Pause and resume
Generators are single-use
A generator object is an iterator. Once it is exhausted, asking for another value raises StopIteration. Create a new generator if you need to traverse the data again. This is different from a list, which can be iterated repeatedly.
def pair():
yield 1
yield 2
gen = pair()
print(list(gen))
print(list(gen))The second pass is empty
Use expressions for short pipelines
A generator expression is compact when the transformation is simple. Parentheses are enough; you do not need a named function. The expression is still lazy, so wrapping it in list or sum is what actually requests values.
squares = (n * n for n in range(4))
print(sum(squares))A one-line lazy pipeline
Chain small stages
A generator can consume another generator. This lets you separate reading, filtering, and formatting without building intermediate lists. Keep each stage small and give it a clear name when the pipeline grows beyond a single expression.
def evens(values):
for value in values:
if value % 2 == 0:
yield value
print(list(evens(range(6))))One stage at a time
Know when a list is better
Generators trade random access and repeatability for lazy memory use. If you need len, indexing, sorting, or several passes, materialize a list. Choose the data structure that matches the next operation, not the one that looks shortest.
values = list(n for n in range(3))
print(len(values))
print(values[1])Materialize when needed
Your practice checklist
- Use yield when values can be produced on demand.
- Call next only when you need one value.
- Create a new generator for a second pass.
- Consume a generator expression with list, sum, or a loop.
- Materialize a list when you need indexing or length.
Common questions
Does a generator run when it is created?
No. Calling the generator function creates an object; the body runs when the generator is advanced.
Can a generator be infinite?
Yes. count and generators with while True can be infinite. Bound them with islice, a break, or another stopping condition.
Is a generator faster than a list?
It can use less memory and avoid building intermediate data, but speed depends on the work. Measure instead of assuming.
Practice generators
12 questions on yield, next, lazy expressions, and generator exhaustion.
Keep reading: