Comprehensions & generator expressions
List, dict and set comprehensions, filtering, nesting, generator expressions and when not to use them.
A comprehension builds a new list, dict or set from an existing iterable in a single, readable expression. They're one of Python's most loved features: shorter than the equivalent loop, often faster, and — once you can read them — very clear. This lesson covers all four kinds, plus when not to use them.
From loop to list comprehension#
Here's a familiar pattern: start with an empty list, loop, append.
The comprehension says the same thing in one line:
Read it as: "a list of n * n, for each n in range(1, 6)". The general shape is:
The expression can be anything — a method call, an f-string, a function call:
Filtering with if#
Add an if at the end to keep only some items:
Transforming conditionally with if … else#
To change every item depending on a condition (rather than drop some), put a conditional expression at the front:
Remember the rule: if after for filters; if … else before for transforms.
Nested loops in a comprehension#
Multiple for clauses nest like loops — left to right is outer to inner:
flat is equivalent to:
Beyond two levels, comprehensions get hard to read — switch to regular loops.
Dict comprehensions#
Use braces with a key: value expression:
(For the last one, dict(zip(codes, names)) is even shorter.)
Set comprehensions#
Braces without a colon build a set — duplicates disappear automatically:
Generator expressions#
Swap the brackets for parentheses and you get a generator expression. It doesn't build a list; it produces values one at a time, on demand:
When a generator expression is the only argument to a function, you can drop the extra parentheses, as in sum(n * n for n in nums). Use generator expressions with sum, min, max, any, all, "".join and anything else that consumes an iterable once. You'll learn how generators work under the hood in a later lesson.
any and all with a generator short-circuit, stopping as soon as the answer is known:
The walrus operator in comprehensions#
The assignment expression := (Python 3.8+) lets you compute a value once and both test and keep it:
Comprehensions have their own scope#
The loop variable doesn't leak out of a comprehension:
When not to use a comprehension#
Comprehensions are for building a collection. Don't use them:
- For side effects —
[print(x) for x in items]builds a useless list ofNones. Use aforloop. - When logic is complex — several conditions, nested
if … else, or more than twoforclauses. A loop with good names is clearer. - When you only need one result — use
any,sum,next(...)with a generator.
Worked example: cleaning survey data#
sum(a == "yes" for a in cleaned) works because True counts as 1 and False as 0.
Common mistakes#
- Putting the filter
ifin front ([x if x > 0 for x in xs]) — that's a syntax error; a frontifneeds anelse. - Expecting
(x for x in xs)to be a tuple — it's a generator. Usetuple(x for x in xs). - Reusing an exhausted generator.
- Cramming too much into one line — readability beats cleverness.
What's next#
Your programs are growing. Next we'll split code across files with modules and packages, and learn exactly how import finds things.
Check your understanding
Quick quiz
1.What does
[n * 2 for n in range(5) if n % 2 == 0]produce?2.What is the key difference between
[x*x for x in data]and(x*x for x in data)?3.Where does the
elsego in a comprehension that transforms every item conditionally?
Finished reading?
Mark this lesson complete to track your progress.