Comprehensions
List, dict, set, and generator comprehensions
A comprehension is a compact way to build a list, dict, set, or generator by transforming and filtering an iterable. Comprehensions are arguably the most Pythonic feature in the language. They turn "loop over this, filter that, transform these" into a single readable expression. Once you internalize the pattern, you will reach for them constantly in data pipelines, API response shaping, config munging, and anywhere you transform collections.
Every snippet on this page runs in your browser — no setup required.
Real-world impact
Comprehensions are everywhere in production Python. Every data pipeline maps and filters rows with comprehensions. Every web API shapes JSON responses with dict comprehensions. Every script that processes files uses comprehensions to filter and transform lines. Mastering comprehensions means writing clearer, faster, more maintainable code.
List comprehensions: basics
The general form:
[expression for item in iterable if condition]A list comprehension is equivalent to:
result = []
for x in iterable:
if condition:
result.append(expression)The comprehension is usually preferable because it states what you want rather than how. It is also often faster because the loop is optimized at the C level.
List comprehensions: with filter
The if clause is optional.
You can combine transformation and filtering.
List comprehensions: nested loops
Multiple for clauses behave like nested loops, left to right.
Nested comprehensions are useful for flattening lists.
Readability ceiling
Comprehensions are powerful, but stacking too much logic into one makes for unreadable code. Rule of thumb: up to one for and one if is usually fine. More than that, or a complex expression, and you should write a loop. Comprehensions are for clarity, not cleverness.
Dict comprehensions
Use {key: value for ...} to build a dict.
Inverting a dict is a one-liner.
Dict comprehensions are especially useful when reshaping API responses or config files.
Set comprehensions
Use {expression for ...} to build a set.
Set comprehensions automatically deduplicate, just like constructing set([...]) would.
Generator expressions
Drop the brackets and you get a generator expression instead. It produces items lazily, one at a time, which is great for memory efficiency.
The results are identical, but the generator uses O(1) memory while the list uses O(n).
Generator vs list memory
A list comprehension builds the entire list in memory before you can use it. A generator expression produces values on demand, one at a time. If you only need to iterate once (e.g., in sum, max, any, all), use a generator. If you need to iterate multiple times or slice the result, use a list.
When a generator expression is the only argument to a function, the inner parentheses can be dropped:
This is equivalent to sum((x * x for x in range(10))) but cleaner.
When to use each form
| Form | Use when |
|---|---|
List comprehension [...] | You need the full list, or will iterate multiple times |
Dict comprehension {k: v ...} | Building or transforming dicts |
Set comprehension {...} | Building a set, deduplication is important |
Generator expression (...) | One-time iteration, memory efficiency matters |
Challenges
Define even_squares(n) that returns a list of the squares of every even number from 0 to n-1, in order. Use a single list comprehension.
Define group_by_length(words) that returns a dict mapping each word length to a list of words with that length, preserving the input order within each group.
For example, group_by_length(["a", "bb", "cc", "d"]) returns {1: ["a", "d"], 2: ["bb", "cc"]}.
A regular loop is fine here; you do not have to use a single comprehension.
Define cartesian(a, b) that returns a list of all (x, y) pairs where x is from list a and y is from list b, in the order produced by nested loops. Use a single list comprehension with two for clauses.
For example, cartesian([1, 2], ["a", "b"]) returns [(1, "a"), (1, "b"), (2, "a"), (2, "b")].
What does [x * 2 for x in range(4) if x % 2] evaluate to?
[0, 2, 4, 6]
[2, 6]
[1, 3]
[0, 4]
Which of the following produces the same result as [x*x for x in range(5)]?
(x*x for x in range(5))
{x*x for x in range(5)}
list(x*x for x in range(5))
{x: x*x for x in range(5)}
What is the key advantage of a generator expression over a list comprehension?
Generators are always faster.
Generators use O(1) memory regardless of input size.
Generators support slicing.
Generators automatically deduplicate.
What does this nested comprehension produce?
[x + y for x in [1, 2] for y in [10, 20]]
[11, 22]
[11, 21, 12, 22]
[11, 12, 21, 22]
[30, 40]
You can now turn raw iterables into shaped data in one line. Functions are next.