Python List Comprehensions Cheat Sheet
Python comprehension syntax covering basic list comprehensions, conditional logic, nested comprehensions, dict/set comprehensions, and generator expressions.
Basic List Comprehensions
Building lists from an iterable in a single expression.
squares = [x ** 2 for x in range(10)]# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]evens = [x for x in range(20) if x % 2 == 0]pairs = [(x, y) for x in range(3) for y in range(3)]# [(0,0), (0,1), (0,2), (1,0), ...]
Conditional Logic
Ternary expressions inside comprehensions vs. filtering.
# ternary expression -> transforms every elementlabels = ["even" if x % 2 == 0 else "odd" for x in range(5)]# trailing if -> filters which elements are includedevens_only = [x for x in range(10) if x % 2 == 0]# combining bothresult = [x if x > 0 else 0 for x in [-2, -1, 0, 1, 2] if x != 0]
Nested Comprehensions
Flattening and transforming nested structures like matrices.
matrix = [[1, 2, 3], [4, 5, 6]]flat = [num for row in matrix for num in row]# [1, 2, 3, 4, 5, 6]transposed = [[row[i] for row in matrix] for i in range(3)]# [[1, 4], [2, 5], [3, 6]]
Dict & Set Comprehensions
The same syntax works for dict and set literals.
squares_dict = {x: x ** 2 for x in range(5)}# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}unique_lengths = {len(word) for word in ["hi", "bye", "ok"]}# {2, 3}swapped = {v: k for k, v in {"a": 1, "b": 2}.items()}# {1: 'a', 2: 'b'}
Generator Expressions
Lazily-evaluated comprehensions that don't build a full list in memory.
gen = (x ** 2 for x in range(10)) # parentheses, not bracketsnext(gen) # 0next(gen) # 1# memory-efficient for large rangestotal = sum(x ** 2 for x in range(1_000_000))
Walrus Operator Inside Comprehensions
Assignment expressions (PEP 572) avoid recomputing an expensive value in filter and output.
data = ["1", "x", "42", "y", "7"]# without walrus: parse_int(v) is called twice per elementresults = [n for v in data if (n := parse_int(v)) is not None]def parse_int(v): try: return int(v) except ValueError: return None# results == [1, 42, 7]
Comprehension Scoping Rules
Since Python 3, comprehensions have their own scope and don't leak loop variables.
x = "outer"values = [x for x in range(3)]print(x) # 'outer' -- unaffected, unlike a plain for loopprint(values) # [0, 1, 2]# but the FIRST iterable expression is still evaluated in the enclosing scopedef make_list(n): return [i * n for i in range(n)] # n is looked up in enclosing scope, fine# a lambda closing over a comprehension variable captures by reference, not valuefuncs = [lambda: i for i in range(3)][f() for f in funcs] # [2, 2, 2] -- all closures see the final i
Comprehensions vs map()/filter() Performance
Comprehensions are usually faster than map+filter with lambdas because they avoid a Python-level function call per element.
import timeitdata = range(100_000)# comprehension: one bytecode loop, no per-element function call overheadt1 = timeit.timeit(lambda: [x * 2 for x in data if x % 2 == 0], number=100)# map/filter with lambdas: extra call overhead per elementt2 = timeit.timeit(lambda: list(map(lambda x: x * 2, filter(lambda x: x % 2 == 0, data))), number=100)# comprehensions typically win unless map() is given a builtin (e.g. map(str, data))
Flattening with itertools.chain.from_iterable
A comprehension-friendly, memory-efficient alternative to nested comprehensions for flattening.
from itertools import chainnested = [[1, 2], [3, 4, 5], [6]]# nested comprehensionflat_a = [x for sub in nested for x in sub]# chain.from_iterable -- lazy, avoids building intermediate listsflat_b = list(chain.from_iterable(nested))# both give [1, 2, 3, 4, 5, 6], chain scales better for many/large sublists
Advanced Comprehension Notes
Lesser-known behaviors and idioms once basic comprehensions are second nature.
- Async comprehensions- `[x async for x in aiter]` iterates an async iterable inside an async def; requires PEP 530 support (Python 3.6+)
- Comprehension inside a class body- the iterable expression can see class-level names, but the loop body cannot see other class attributes directly due to scoping
- Multiple if clauses- `[x for x in data if a(x) if b(x)]` is equivalent to `if a(x) and b(x)` but reads as successive filters
- Comprehensions and exceptions- an exception raised inside a comprehension propagates immediately and the partial result is discarded
- Set comprehension dedup cost- `{f(x) for x in data}` still calls f(x) for every element even if many hash to the same value
- Dict comprehension key collisions- later duplicate keys silently overwrite earlier ones, iteration order determines which value wins
If a comprehension needs more than two nested `for` clauses or a complex condition, rewrite it as a regular loop — readability drops fast past that point, and a plain loop with clear variable names will be easier to debug.