Comprehensions — Lists, Dicts, Sets & Generator Expressions
IntermediateComprehensions build collections declaratively — [x*2 for x in nums if x > 0] — replacing 4-line loops with one readable line, with dict/set variants and lazy generator expressions.
Overview
Comprehensions are Python's signature idiom: transform + filter a collection in one expression that reads like math set notation. They are usually faster than equivalent for-loops (the loop runs in C), exist for lists, dicts and sets, and their lazy sibling — the generator expression — processes unlimited data in constant memory. Rule of taste: one, maybe two clauses. If a comprehension needs a paragraph to understand, write a loop.
The Anatomy: [expression for item in iterable if condition]
Map (expression), loop (for), filter (if) — in that order. An if/else BEFORE the for is a value choice; an if AFTER is a filter. Nesting reads left-to-right like nested loops.
nums = [3, -1, 8, -5, 12]
positives_doubled = [n * 2 for n in nums if n > 0] # [6, 16, 24]
# if/else as VALUE (before for) vs if as FILTER (after)
labels = ["pos" if n > 0 else "neg" for n in nums]
evens = [n for n in nums if n % 2 == 0]
# Dict & set comprehensions
squares = {n: n * n for n in range(5)}
lengths = {len(w) for w in ["go", "py", "java"]} # {2, 4}
inverted = {v: k for k, v in {"a": 1, "b": 2}.items()}
# Flatten a matrix — nested fors read left to right
matrix = [[1, 2], [3, 4], [5, 6]]
flat = [x for row in matrix for x in row] # [1,2,3,4,5,6]
# Same as:
# for row in matrix:
# for x in row: ...Generator Expressions — Lazy Comprehensions
Round brackets make a generator: values are produced one at a time, on demand — constant memory. Feed them directly to sum/max/any/all without materializing a list.
# List comp: builds ALL 10 million values in memory
# total = sum([n * n for n in range(10_000_000)])
# Generator expression: one value at a time — same result, ~no memory
total = sum(n * n for n in range(10_000_000))
# any/all short-circuit beautifully with generators
nums = [4, 8, 15, 16, 23, 42]
print(any(n > 40 for n in nums)) # True — stops at 42
print(all(n % 2 == 0 for n in nums)) # False — stops at 15
# Read a huge file lazily: total chars in long lines
# long = sum(len(line) for line in open("big.log") if len(line) > 80)
# A generator is one-shot
g = (n * 2 for n in [1, 2, 3])
print(list(g)) # [2, 4, 6]
print(list(g)) # [] — exhausted!Key Points to Remember
- 1Order: expression → for → if(filter); if/else before the for is a value expression
- 2Dict: {k: v for ...}; set: {x for ...}; generator: (x for ...)
- 3Generator expressions are lazy and one-shot — perfect inside sum/any/all/max
- 4Two clauses max for readability — beyond that, write the loop
Interview Questions
Sign in to ask AriaFlatten a list of lists with a comprehension — and explain the clause order.
List comprehension vs generator expression — memory and reuse differences?
Invert a dictionary (values become keys) in one line. What could go wrong?
Ask Aria about Comprehensions — Lists, Dicts, Sets & Generator Expressions
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.