Focused practice · 9 min read

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

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.

Open practice

Keep reading: