List comprehensions
A list comprehension builds a new list from any iterable in one expression. Instead of writing a for loop that appends to an empty list each iteration, you write the whole thing inline.
# Loop versionsquares = []for x in range(6): squares.append(x ** 2)
# Comprehension — same result, one linesquares = [x ** 2 for x in range(6)]# → [0, 1, 4, 9, 16, 25]The general shape is:
[<expression> for <item> in <iterable>][<expression> for <item> in <iterable> if <condition>]The if condition is optional. Leave it out when you want every element.
Filtering with if
Section titled “Filtering with if”Add a condition at the end to keep only elements that match:
nums = [1, 2, 3, 4, 5, 6]
evens = [x for x in nums if x % 2 == 0]# → [2, 4, 6]
long_words = [w for w in ["hi", "hello", "hey", "howdy"] if len(w) > 3]# → ["hello", "howdy"]The loop equivalent makes the evaluation order clear: Python checks the condition first, then appends.
evens = []for x in nums: if x % 2 == 0: # check condition evens.append(x)Transform and filter in one expression
Section titled “Transform and filter in one expression”Put the transform expression at the front and the if condition at the end to do both in one go:
nums = [1, 2, 3, 4, 5, 6]
even_squares = [x ** 2 for x in nums if x % 2 == 0]# ^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^# result source filter# → [4, 16, 36]Compared to map() + filter(), which does the same work but reads right to left:
# These produce the same result:result = list(map(lambda x: x**2, filter(lambda x: x % 2 == 0, nums)))result = [x**2 for x in nums if x % 2 == 0]
# The comprehension reads left to right: result, source, condition.# map + filter reads inside out: filter first (inner), then map (outer). Input: [1, 2, 3, 4, 5, 6]
═══════════════════════════════════════════════════════════════ map() + filter() List comprehension ═══════════════════════════════════════════════════════════════
filter(lambda x: x % 2 == 0) if x % 2 == 0 ───────────────────────────── ───────────── [ 1 ] ── False ── ✗ [ 1 ] ── False ── ✗ [ 2 ] ── True ── [ 2 ] ──┐ [ 2 ] ── True ── [ 2 ] ──┐ [ 3 ] ── False ── ✗ │ [ 3 ] ── False ── ✗ │ [ 4 ] ── True ── [ 4 ] ──┤ [ 4 ] ── True ── [ 4 ] ──┤ [ 5 ] ── False ── ✗ │ [ 5 ] ── False ── ✗ │ [ 6 ] ── True ── [ 6 ] ──┤ [ 6 ] ── True ── [ 6 ] ──┤ │ │ map(lambda x: x**2) │ x ** 2 │ ─────────────────── ┤ ──────────────── ─┤ [ 2 ] ── (x**2) ── [ 4 ] ──┐ [ 2 ] ── (x**2) ── [ 4 ] ──┐ [ 4 ] ── (x**2) ── [ 16 ] ──┤ [ 4 ] ── (x**2) ── [ 16 ] ──┤ [ 6 ] ── (x**2) ── [ 36 ] ──┤ [ 6 ] ── (x**2) ── [ 36 ] ──┤ │ │ [4, 16, 36] [4, 16, 36]Same steps, same result. The comprehension is not faster; it just reads in a more natural order.
Flattening a nested list
Section titled “Flattening a nested list”Two for clauses in one comprehension let you iterate over nested structure. The outer clause comes first, the inner one second:
nested = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]
flat = [x for sublist in nested for x in sublist]# ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^# outer: each sublist inner: each item in it# → [1, 2, 3, 4, 5, 6, 7, 8, 9]Reading it as two stacked for lines, top to bottom, shows what the comprehension expands to:
flat = []for sublist in nested: # outer clause for x in sublist: # inner clause flat.append(x)Set and dict comprehensions
Section titled “Set and dict comprehensions”The same syntax works for sets and dicts. Only the brackets change:
nums = [1, 2, 3, 4, 5]
# List — ordered, allows duplicatessquares_list = [x ** 2 for x in nums]# → [1, 4, 9, 16, 25]
# Set — unordered, no duplicatessquares_set = {x ** 2 for x in nums}# → {1, 4, 9, 16, 25}
# Dict — key: value pairssquares_dict = {x: x ** 2 for x in nums}# → {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}The uniqueness of sets matters when your input has duplicates. A list comprehension keeps them; a set comprehension drops them:
nums = [1, 2, 2, 3, 3, 3]
print([x ** 2 for x in nums]) # [1, 4, 4, 9, 9, 9] ← duplicates keptprint({x ** 2 for x in nums}) # {1, 4, 9} ← duplicates dropped Input: [1, 2, 3, 4, 5]
═════════════════════════════════════════════════════════════════════ List comprehension Set comprehension Dict comprehension [x**2 for x in nums] {x**2 for x in nums} {x: x**2 for x in nums} ═════════════════════════════════════════════════════════════════════
[ 1 ] ── (x**2) ── 1 1 (unique) 1 ──► 1 [ 2 ] ── (x**2) ── 4 4 (unique) 2 ──► 4 [ 3 ] ── (x**2) ── 9 9 (unique) 3 ──► 9 [ 4 ] ── (x**2) ── 16 16 (unique) 4 ──► 16 [ 5 ] ── (x**2) ── 25 25 (unique) 5 ──► 25 │ │ │ ▼ ▼ ▼ [1, 4, 9, {1, 4, 9, {1:1, 2:4, 3:9, 16, 25] 16, 25} 4:16, 5:25}
ordered unordered, no duplicates key: value pairs bracket [] curly braces {} curly braces {key: value}Lazy vs eager
Section titled “Lazy vs eager” Input: [1, 2, 3, 4, 5]
═══════════════════════════════════════════════════════════════ map() — lazy List comprehension — eager ═══════════════════════════════════════════════════════════════
map(lambda x: x**2, nums) [x**2 for x in nums]
returns immediately ──► <map object> returns immediately ──► [1, 4, 9, 16, 25] │ │ nothing computed fully computed values sit waiting all in memory │ only computes when consumed │ next() ──► 1 (rest still waiting) next() ──► 4 (rest still waiting) next() ──► 9 (rest still waiting) ...
═══════════════════════════════════════════════════════════════ Memory cost one value at a time all N values at once Best when large data, early exit small data, need all values ═══════════════════════════════════════════════════════════════Comprehension vs map() / filter()
Section titled “Comprehension vs map() / filter()”Both approaches do the same work. The choice is mostly stylistic:
| Goal | map / filter | Comprehension |
|---|---|---|
| Transform | map(lambda x: x**2, nums) | [x**2 for x in nums] |
| Filter | filter(lambda x: x>3, nums) | [x for x in nums if x>3] |
| Both | map(..., filter(..., nums)) | [x**2 for x in nums if x>3] |
| Reduce | reduce(lambda a,x: a+x, nums) | No equivalent |
map() can be shorter when you already have a named function, since you can pass it without a lambda:
words = ["hello", "world"]
list(map(str.upper, words)) # ["HELLO", "WORLD"] — no lambda needed[w.upper() for w in words] # same result, method call stylereduce() has no comprehension equivalent. It stays the right tool whenever you need to collapse a collection into a single value.