Python List Comprehension
A list comprehension builds a new list from an existing one in a single, readable line. It replaces the common “empty list, loop, append” pattern and is one of the features that makes Python code short.
- Turn a for loop into a comprehension
- Filter items with if
- Choose values with if-else
- Build sets and dicts the same way
From loop to comprehension
Here is the familiar pattern: start with an empty list, loop, and append.
numbers = [1, 2, 3, 4, 5]squares = []for n in numbers: squares.append(n * n)print(squares)[1, 4, 9, 16, 25]
The comprehension says the same thing in one line. Read it as “n times n, for each n in numbers“:
numbers = [1, 2, 3, 4, 5]squares = [n * n for n in numbers]print(squares)[1, 4, 9, 16, 25]
The general form is [expression for item in iterable].
Filter with if
Add if condition at the end to keep only some items.
scores = [45, 82, 67, 91, 38, 74]passed = [s for s in scores if s >= 50]print(passed) words = ["api", "", "ui", " ", "db"]clean = [w for w in words if w.strip()]print(clean)[82, 67, 91, 74] ['api', 'ui', 'db']
Choose a value with if-else
To transform every item one of two ways, put a conditional expression at the front. Note the different position from the filter above.
scores = [45, 82, 67, 91, 38]labels = ["pass" if s >= 50 else "fail" for s in scores]print(labels)['fail', 'pass', 'pass', 'pass', 'fail']
if at the end filters (fewer items). if ... else at the front maps (same number of items). You can use both: [x * 2 if x > 0 else 0 for x in data if x is not None].
Work with strings
sentence = "Python makes testing simple"print([w.upper() for w in sentence.split()])print([len(w) for w in sentence.split()])print([ch for ch in "a1b2c3" if ch.isdigit()])['PYTHON', 'MAKES', 'TESTING', 'SIMPLE'] [6, 5, 7, 6] ['1', '2', '3']
Nested comprehensions
Two for clauses work like nested loops, read from left to right:
pairs = [(x, y) for x in [1, 2, 3] for y in "ab"]print(pairs) matrix = [[1, 2, 3], [4, 5, 6]]flat = [n for row in matrix for n in row]print(flat) transposed = [[row[i] for row in matrix] for i in range(3)]print(transposed)[(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b')] [1, 2, 3, 4, 5, 6] [[1, 4], [2, 5], [3, 6]]
If a comprehension needs more than two for clauses or a long condition, write a normal loop. Readability counts more than saving lines.
Set and dict comprehensions
Use { } to build a set, and {key: value ...} to build a dict.
emails = ["a@x.com", "b@y.com", "c@x.com"]domains = {e.split("@")[1] for e in emails}print(sorted(domains)) prices = {"pen": 10, "book": 120, "bag": 650}with_tax = {item: round(p * 1.18, 2) for item, p in prices.items()}print(with_tax) expensive = {k: v for k, v in prices.items() if v > 100}print(expensive)['x.com', 'y.com']
{'pen': 11.8, 'book': 141.6, 'bag': 767.0}
{'book': 120, 'bag': 650}Generator expressions
With round brackets you get a generator expression. It produces values one at a time instead of building a list, which saves memory when you only need to consume the values once, for example in sum():
print(sum(n * n for n in range(1, 101)))print(any(s < 40 for s in [45, 82, 38]))338350 True
The Generators lesson explains how this works.
Check your understanding
Predict the output
data = [3, -1, 0, 8, -5]print([abs(x) for x in data if x != 0], [x if x > 0 else 0 for x in data])[3, 1, 8, 5] [3, 0, 0, 8, 0]
The first comprehension filters out the 0 and takes absolute values. The second keeps all five items but replaces non-positive ones with 0.
Quick quiz
1. What does [x * 2 for x in range(3)] produce?
range(3) is 0, 1, 2 and each is doubled.
2. Where does a filtering if go?
[x for x in items if condition].
3. Which builds a set?
Curly braces without key: value make a set comprehension; round brackets make a generator.
Exercise: even squares and word lengths
Build a list of the squares of the even numbers from 1 to 10, and a dict mapping each word to its length.
range 1 to 10; words = ["login", "cart", "checkout"]
[4, 16, 36, 64, 100]
{'login': 5, 'cart': 4, 'checkout': 8}Hint 1
Filter with if n % 2 == 0.
Hint 2
A dict comprehension looks like {w: len(w) for w in words}.
even_squares = [n * n for n in range(1, 11) if n % 2 == 0]print(even_squares) words = ["login", "cart", "checkout"]lengths = {w: len(w) for w in words}print(lengths)[4, 16, 36, 64, 100]
{'login': 5, 'cart': 4, 'checkout': 8}The filter runs before the expression, so only 2, 4, 6, 8 and 10 are squared. The dict comprehension uses each word as a key and its length as the value.
Program Practice
Many list programs can be solved in one line with a comprehension. Solve each one with a loop first, then rewrite it.
100 Python List Programs
Every program has a step-by-step explanation, colour-coded code and its real output.
Python list comprehension FAQ
Is list comprehension faster than a for loop?
Usually a little, because the append happens inside the interpreter. Choose it for readability first; the speed gain is small.
Can I use else in a list comprehension?
Yes, as part of a conditional expression at the front: [a if cond else b for x in items]. A filtering if at the end cannot have an else.
What is the difference between a list comprehension and a generator expression?
A list comprehension [...] builds the whole list in memory. A generator expression (...) yields items one at a time, which is better for large data that you only loop over once.