Comprehensions are one of Python’s superpowers. They let us create lists, dicts, and sets in a single readable line instead of writing a full loop. Once we get the hang of them, we’ll use them everywhere.
List Comprehensions
The basic pattern is [expression for item in iterable].
# Without comprehension
squares = []
for n in range(1, 6):
squares.append(n ** 2)
# With comprehension — same result, one line
squares = [n ** 2 for n in range(1, 6)]
# [1, 4, 9, 16, 25]
Adding Conditions
We can filter items with an if clause.
# Only even numbers
evens = [n for n in range(10) if n % 2 == 0]
# [0, 2, 4, 6, 8]
# Only words longer than 3 characters
words = ["hi", "hello", "hey", "howdy"]
long_words = [w for w in words if len(w) > 3]
# ['hello', 'howdy']
We can also use if-else — but notice it goes before the for, not after.
labels = ["even" if n % 2 == 0 else "odd" for n in range(5)]
# ['even', 'odd', 'even', 'odd', 'even']
Nested Comprehensions
We can flatten nested loops into a single comprehension. The order reads left to right, just like nested for loops.
# Flatten a 2D list
matrix = [[1, 2], [3, 4], [5, 6]]
flat = [num for row in matrix for num in row]
# [1, 2, 3, 4, 5, 6]
# All (x, y) pairs
pairs = [(x, y) for x in range(3) for y in range(3)]
# [(0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), (2,2)]
Dict Comprehensions
Same idea, but we produce key-value pairs.
names = ["alice", "bob", "charlie"]
name_lengths = {name: len(name) for name in names}
# {'alice': 5, 'bob': 3, 'charlie': 7}
# Filter while building
scores = {"math": 90, "art": 60, "science": 85}
passed = {k: v for k, v in scores.items() if v >= 70}
# {'math': 90, 'science': 85}
Set Comprehensions
Like list comprehensions but with curly braces. Duplicates are automatically removed.
words = ["hello", "world", "hello", "python"]
unique_lengths = {len(w) for w in words}
# {5, 6} — only unique lengths
Generator Expressions (Lazy Comprehensions)
If we use parentheses instead of brackets, we get a generator expression. It doesn’t build the whole list in memory — it produces values one at a time.
# This creates a list in memory
total = sum([n ** 2 for n in range(1_000_000)])
# This is lazy — uses almost no memory
total = sum(n ** 2 for n in range(1_000_000))
The only difference is [] vs (). Generator expressions are great when we’re passing data to a function like sum(), max(), or any() and don’t need the intermediate list.
When NOT to Use Comprehensions
Comprehensions are awesome, but they can hurt readability when:
- The logic is complex (multiple conditions, nested transformations)
- We need side effects (like printing or modifying external state)
- The line gets too long (if we need to scroll, use a loop instead)
In simple language, if we can say “give me X for each Y” in English, it probably fits in a comprehension. If we need to explain it in a paragraph, use a regular loop.