List Comprehensions
Build a list in one readable line
In this lesson
A list comprehension is a short, readable way to build a new list from an existing one in a single line. It’s an extremely common Python pattern — once you can read them, you’ll see them everywhere.
Explain it like I’m 5
A comprehension is a sentence: ‘give me X for each item in this list’. It’s a compact way to say what would otherwise be a little loop that builds a new list.
From loop to comprehension
The long way to square a list is: make an empty list, loop, and append each squared value. A comprehension says the same thing in one line: [n * n for n in numbers]. Read it as ‘n * n for each n in numbers’. The expression on the left is what goes into the new list.
# The long way
squares = []
for n in [1, 2, 3, 4]:
squares.append(n * n)
print(squares)
# The comprehension — same result, one line
squares = [n * n for n in [1, 2, 3, 4]]
print(squares)
[1, 4, 9, 16] [1, 4, 9, 16]
Adding a filter
You can keep only some items by adding if: [n for n in numbers if n % 2 == 0] builds a list of just the even numbers. The structure is ‘expression for item in collection if condition’. The condition decides which items make it in; the expression decides what they become.
numbers = [1, 2, 3, 4, 5, 6]
squares = [n * n for n in numbers]
evens = [n for n in numbers if n % 2 == 0]
print(squares)
print(evens)
[1, 4, 9, 16, 25, 36] [2, 4, 6]
Use a list comprehension to build a list of the lengths of each word, but only for words longer than 3 letters.
words = ["cat", "tiger", "ox", "panther", "ant"]
# lengths of words longer than 3 letters
result = []
print(result)
[len(w) for w in words if len(w) > 3] — the expression is len(w) and the filter keeps long words.
words = ["cat", "tiger", "ox", "panther", "ant"]
result = [len(w) for w in words if len(w) > 3]
print(result)
[5, 7]
When to use one — and when not to
Comprehensions shine for simple transform-and-filter tasks: they’re shorter and signal intent clearly. But if the logic is complicated — multiple conditions, side effects, nested loops several levels deep — a plain for loop is more readable. Favour clarity over cleverness; a comprehension that’s hard to read has missed the point.
Dict and set comprehensions
The same idea works for dictionaries and sets. {name: len(name) for name in names} builds a dict mapping each name to its length. {n % 3 for n in numbers} builds a set. The curly braces and the key: value form are the only differences — the ‘for each’ thinking is identical.
words = ["hi", "hello", "hey", "howdy"]
lengths = {w: len(w) for w in words}
print(lengths)
{'hi': 2, 'hello': 5, 'hey': 3, 'howdy': 5}
Generator expressions: comprehensions without the list
Swap a comprehension’s square brackets for parentheses and you get a generator expression. Instead of building the whole list in memory, it produces items one at a time, on demand. That’s perfect when you only need to feed values into something like sum(), max(), or any(), or when the sequence is enormous.
sum(n * n for n in range(1000)) adds a thousand squares without ever storing a thousand-item list. (The { } versions you met earlier — set and dict comprehensions — build collections the same lazy-free way.)
numbers = [1, 2, 3, 4, 5]
# A list comprehension builds the whole list:
squares = [n * n for n in numbers]
print(squares)
# A generator expression feeds sum() one value at a time:
total = sum(n * n for n in numbers)
print(total)
[1, 4, 9, 16, 25] 55
Common mistake: Cramming complex logic into a comprehension
It’s tempting to keep adding conditions and nesting until the line is unreadable, prizing brevity over clarity.
If a comprehension needs multiple conditions or nested loops to follow, rewrite it as a normal for loop. Readable beats clever.
Common mistake: Putting the filter in the wrong place
A simple if that selects items goes at the end; an if/else that chooses the value goes before the for. Mixing these up is a common confusion.
To filter: [x for x in items if cond]. To choose a value: [a if cond else b for x in items].
What does [n * 2 for n in [1, 2, 3]] produce?
It doubles each item, giving [2, 4, 6].
Where does a filtering condition go in a comprehension?
A selecting if goes after the for clause, at the end.
Mini exercise (medium)
Given temps_c = [0, 20, 37, 100], use a list comprehension to build the same temperatures in Fahrenheit (c * 9 / 5 + 32).
Do it here. Finish the code below and press Run to try your answer right in the browser — no setup needed.
temps_c = [0, 20, 37, 100]
temps_f = [] # TODO: list comprehension c * 9 / 5 + 32
print(temps_f)
The expression is the formula: [c * 9 / 5 + 32 for c in temps_c].
temps_c = [0, 20, 37, 100]
temps_f = [c * 9 / 5 + 32 for c in temps_c]
print(temps_f)
__no_output_bypass__ = True
import ast as _ast
assert any(isinstance(n, _ast.ListComp) for n in _ast.walk(_ast.parse(__user_code__))), "use a list comprehension [ ... for ... in ... ], not a for loop"
__no_output_bypass__ = False
assert [round(t, 4) for t in temps_f] == [32.0, 68.0, 98.6, 212.0], "0, 20, 37 and 100 C become 32, 68, 98.6 and 212 F"
print("✓ Converted!")