Python Comprehensions Cheat Sheet
A complete reference for Python list, dict, set comprehensions, generator expressions, conditionals, nested patterns, and performance.
📖List Comprehension
The most common and versatile comprehension — weave lists from iterables.
Basic list comprehension. Creates a new list by iterating over an iterable and collecting each element.
nums = [1, 2, 3, 4, 5] result = [x for x in nums] print(result) # [1, 2, 3, 4, 5]
Filter elements with a condition. Only items where the condition is True are included.
nums = [1, 2, 3, 4, 5, 6] evens = [x for x in nums if x % 2 == 0] print(evens) # [2, 4, 6]
Inline if-else to transform elements conditionally. The ternary expression goes before the for clause.
nums = [1, 2, 3, 4, 5] labels = ["even" if x % 2 == 0 else "odd" for x in nums] print(labels) # ['odd', 'even', 'odd', 'even', 'odd']
Transform each element during collection. Apply any expression or function call to the item.
nums = [1, 2, 3, 4] doubled = [x * 2 for x in nums] print(doubled) # [2, 4, 6, 8] words = ["a", "bb", "ccc"] lengths = [len(w) for w in words] print(lengths) # [1, 2, 3]
Flatten a nested list (matrix) into a single list. Multiple for clauses read left to right like nested loops.
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] flat = [item for sublist in matrix for item in sublist] print(flat) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
Cartesian product — combine elements from multiple iterables. Equivalent to nested for loops.
a = [1, 2] b = [10, 20] sums = [x + y for x in a for y in b] print(sums) # [11, 21, 12, 22]
Use enumerate inside a comprehension to get both index and value.
items = ["apple", "banana", "cherry"] numbered = [f"{i}: {v}" for i, v in enumerate(items)] print(numbered) # ['0: apple', '1: banana', '2: cherry']
Use zip to iterate over multiple lists in parallel inside a comprehension.
names = ["Alice", "Bob"] scores = [95, 87] pairs = [f"{n}: {s}" for n, s in zip(names, scores)] print(pairs) # ['Alice: 95', 'Bob: 87']
Combine range with comprehension to generate sequences of transformed numbers.
squares = [x**2 for x in range(10)] print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] odds = [x for x in range(20) if x % 2 == 1] print(odds) # [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
Apply string methods or any object method inside a comprehension.
words = ["hello", "world"] upper = [s.upper() for s in words] print(upper) # ['HELLO', 'WORLD'] stripped = [s.strip() for s in [" a ", " b "]] print(stripped) # ['a', 'b']
Chain multiple if conditions. Both conditions must be True for the element to be included.
nums = [-4, -2, 0, 1, 2, 3, 4] result = [x for x in nums if x > 0 if x % 2 == 0] print(result) # [2, 4]
List comprehensions are generally preferred over map/filter for readability and speed.
nums = [1, 2, 3, 4, 5] # List comprehension (preferred) evens_sq = [x**2 for x in nums if x % 2 == 0] # Equivalent with map/filter evens_sq2 = list(map(lambda x: x**2, filter(lambda x: x % 2 == 0, nums)))
📜Dict Comprehension
Weave dictionaries with key-value pairs from any iterable.
Basic dict comprehension from two parallel iterables using zip.
keys = ["a", "b", "c"] values = [1, 2, 3] d = {k: v for k, v in zip(keys, values)} print(d) # {'a': 1, 'b': 2, 'c': 3}
Create a dict from a single iterable, using the element as both key and transformed value.
squares = {x: x**2 for x in range(5)} print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} chars = {c: ord(c) for c in "abc"} print(chars) # {'a': 97, 'b': 98, 'c': 99}
Filter a dictionary by its values (or keys) using a condition.
data = {"a": 1, "b": -2, "c": 3, "d": -4} positive = {k: v for k, v in data.items() if v > 0} print(positive) # {'a': 1, 'c': 3}
Invert a dictionary — swap keys and values. Values must be unique and hashable.
original = {"a": 1, "b": 2, "c": 3} inverted = {v: k for k, v in original.items()} print(inverted) # {1: 'a', 2: 'b', 3: 'c'}
Use inline if-else to conditionally transform values while keeping all keys.
data = {"a": 1, "b": -2, "c": 3} clamped = {k: (v if v > 0 else 0) for k, v in data.items()} print(clamped) # {'a': 1, 'b': 0, 'c': 3}
Dict comprehension alternative for grouping. Note: comprehensions cannot easily group, use a loop for that.
items = [("fruit", "apple"), ("veg", "carrot"), ("fruit", "banana")] # Use a loop for grouping groups = {} for k, v in items: groups.setdefault(k, []).append(v) print(groups) # {'fruit': ['apple', 'banana'], 'veg': ['carrot']}
Merge multiple dictionaries with a comprehension. Later dicts overwrite earlier ones for duplicate keys.
dicts = [{"a": 1}, {"b": 2}, {"a": 3}] merged = {k: v for d in dicts for k, v in d.items()} print(merged) # {'a': 3, 'b': 2}
Nested dict comprehension to create a 2D lookup table or matrix of dictionaries.
table = {i: {j: i*j for j in range(3)} for i in range(3)} print(table) # {0: {0: 0, 1: 0, 2: 0}, 1: {0: 0, 1: 1, 2: 2}, 2: {0: 0, 1: 2, 2: 4}}
🔷Set Comprehension
Weave unique collections with automatic deduplication.
Basic set comprehension. Creates a set, automatically removing duplicates.
nums = [1, 2, 2, 3, 3, 3] unique = {x for x in nums} print(unique) # {1, 2, 3}
Filter elements while building a set. Only unique values passing the condition are kept.
nums = [-2, -1, 0, 1, 2, 3] positive = {x for x in nums if x > 0} print(positive) # {1, 2, 3}
Deduplicate strings case-insensitively by normalizing before adding to the set.
words = ["Apple", "apple", "APPLE", "Banana"] normalized = {x.lower() for x in words} print(normalized) # {'apple', 'banana'}
Set comprehensions are often clearer than passing a generator to set(), especially with conditions.
nums = [1, 2, 3, 4, 5] # Set comprehension (preferred) evens = {x for x in nums if x % 2 == 0} # Equivalent with set() evens2 = set(x for x in nums if x % 2 == 0)
Use set comprehensions for mathematical set construction like squares, primes, or multiples.
squares = {x**2 for x in range(10)} print(squares) # {0, 1, 4, 9, 16, 25, 36, 49, 64, 81} multiples_of_3 = {x for x in range(30) if x % 3 == 0} print(multiples_of_3) # {0, 3, 6, 9, 12, 15, 18, 21, 24, 27}
Flatten and deduplicate in one pass using nested set comprehensions.
matrix = [[1, 2, 2], [3, 3, 4], [1, 4, 5]] unique_flat = {x for row in matrix for x in row} print(unique_flat) # {1, 2, 3, 4, 5}
♻Generator Expression
Lazy evaluation for memory-efficient iteration over large datasets.
Basic generator expression. Returns a generator object, not a list. Values are computed on demand.
gen = (x for x in range(5)) print(gen) # <generator object> print(next(gen)) # 0 print(next(gen)) # 1 print(list(gen)) # [2, 3, 4]
Memory efficiency: generator expressions compute one value at a time, never storing the full sequence.
# Generator — memory efficient total = sum(x**2 for x in range(1000000)) # List comprehension — stores all values total2 = sum([x**2 for x in range(1000000)])
Filter with a generator expression. The condition is evaluated lazily as values are requested.
nums = [-3, -1, 0, 2, 4] positive = (x for x in nums if x > 0) print(list(positive)) # [2, 4]
Chain generator expressions to build data pipelines without intermediate lists.
nums = [-5, -2, 0, 3, 4, 7] pipeline = (x*2 for x in (x for x in nums if x > 0)) print(list(pipeline)) # [6, 8, 14]
Generators shine for large data and single-pass operations. Lists are better for repeated access or indexing.
import sys gen = (x for x in range(1000000)) lst = [x for x in range(1000000)] print(sys.getsizeof(gen)) # ~112 bytes print(sys.getsizeof(lst)) # ~8,000,000 bytes
Find the first matching element with a default value. Stops at the first match — very efficient.
items = [-5, -2, 0, 3, 4] first_positive = next((x for x in items if x > 0), None) print(first_positive) # 3 # With default when not found first_big = next((x for x in items if x > 100), "not found") print(first_big) # not found
⚙Conditionals & Logic
Filtering and branching inside comprehensions.
Place a single if after the for clause to filter elements. The condition must evaluate to True for inclusion.
nums = [1, 2, 3, 4, 5, 6] evens = [x for x in nums if x % 2 == 0] print(evens) # [2, 4, 6]
Use a ternary expression before the for clause to conditionally transform each element.
nums = [1, 2, 3, 4] result = ["even" if x % 2 == 0 else "odd" for x in nums] print(result) # ['odd', 'even', 'odd', 'even']
Chain multiple if conditions. All conditions must be True (AND logic).
nums = range(20) result = [x for x in nums if x % 2 == 0 if x % 3 == 0 if x > 0] print(result) # [6, 12, 18]
Use the walrus operator (:=) to assign and test in one expression. Python 3.8+.
import re lines = ["abc 123", "no digits", "456 xyz"] matches = [m.group(0) for line in lines if (m := re.search(r'\d+', line))] print(matches) # ['123', '456']
📏Nested Comprehensions
Multi-dimensional weaving with nested loops inside comprehensions.
Transpose a matrix using nested list comprehension. Swap rows and columns.
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] transposed = [[row[i] for row in matrix] for i in range(len(matrix[0]))] print(transposed) # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Create nested dictionaries with comprehensions. Useful for lookup tables and grouping.
table = { i: {f"col_{j}": i * j for j in range(3)} for i in range(3) } print(table) # {0: {'col_0': 0, 'col_1': 0, 'col_2': 0}, ...}
Understand the difference between nested comprehensions and multiple for clauses in one comprehension.
# Nested — produces a list of lists nested = [[i * j for j in range(3)] for i in range(3)] print(nested) # [[0, 0, 0], [0, 1, 2], [0, 2, 4]] # Flat — produces a single list flat = [i * j for i in range(3) for j in range(3)] print(flat) # [0, 0, 0, 0, 1, 2, 0, 2, 4]
⏱Performance & Patterns
Speed, memory, and when to use (or avoid) comprehensions.
List comprehensions are typically faster than equivalent for loops because the iteration runs in C.
# List comprehension — faster squares = [x**2 for x in range(1000)] # For loop — slower but equivalent squares2 = [] for x in range(1000): squares2.append(x**2) # ~1.5-2x speedup with comprehension
List comprehensions are often faster than map() with lambda, and always more readable.
nums = range(1000) # List comprehension — preferred result = [x**2 for x in nums] # map with lambda — less readable result2 = list(map(lambda x: x**2, nums)) # map with existing function — acceptable result3 = list(map(str, nums))
For large datasets, generator expressions use constant memory regardless of input size.
import sys # Generator — constant memory gen = (x**2 for x in range(10_000_000)) print(sys.getsizeof(gen)) # ~112 bytes # List — proportional memory lst = [x**2 for x in range(10_000_000)] print(sys.getsizeof(lst)) # ~80 MB
Avoid comprehensions for side effects, complex logic, or when readability suffers. Use a plain loop instead.
# BAD: side effect in comprehension [print(x) for x in items] # Creates a list of Nones # GOOD: use a plain loop for x in items: print(x) # BAD: too complex result = [f(x) if cond1(x) else g(x) if cond2(x) else x for x in items] # GOOD: use a function result = [categorize(x) for x in items]
While Counter is best, you can build frequency dicts with comprehensions for simple cases.
from collections import Counter words = ["apple", "banana", "apple", "cherry", "banana", "apple"] # Best: use Counter freq = Counter(words) # Alternative: dict comprehension with count() freq2 = {w: words.count(w) for w in set(words)} print(freq2) # {'apple': 3, 'banana': 2, 'cherry': 1}
Use set comprehensions for O(1) membership tests and deduplication.
items = ["a", "b", "a", "c", "b"] unique = {x for x in items} # Fast membership test print("a" in unique) # True — O(1) # Check if all unique print(len(items) == len(unique)) # False
📊List Comp vs For Loop vs map/filter
When to choose which approach for transforming iterables.
| Approach | Syntax | Speed | Readability | Use Case |
|---|---|---|---|---|
| List comprehension | [f(x) for x in items] | Fastest | Excellent | Most transformations and filters |
| For loop | for x in items: result.append(f(x)) | Slower | Good | Side effects, complex logic |
| map() | map(f, items) | Fast | Poor (with lambda) | Existing function, no filter |
| filter() | filter(cond, items) | Fast | Poor (with lambda) | Existing predicate function |
| map + filter | map(f, filter(cond, items)) | Fast | Very poor | Rarely — use list comp instead |
📊Comprehension Type Comparison
Quick reference for choosing the right comprehension type.
| Type | Syntax | Memory | Evaluation | Use Case |
|---|---|---|---|---|
| List | [x for x in items] | O(n) | Eager | Need all results, indexing, repeated access |
| Dict | {k: v for k, v in items} | O(n) | Eager | Key-value mappings, lookups |
| Set | {x for x in items} | O(n) | Eager | Uniqueness, membership tests |
| Generator | (x for x in items) | O(1) | Lazy | Large data, single-pass, chaining |
🌟Pro Tips
Wisdom from the loom — best practices and gotchas.
[print(x) for x in items] creates a list of Nones — wasteful and confusing.[x for row in matrix for x in row] over nested brackets when flattening.:= lets you assign and test in one expression inside comprehensions. Great for regex matching and expensive computations: [m.group() for line in lines if (m := re.search(..., line))].[categorize(x) for x in items] is cleaner than a 3-level ternary inside brackets.