List Comprehension in Python
A list comprehension builds a new list from an iterable in one expression inside square brackets. [n * n for n in range(5)] does the job of a for loop that appends n * n to an empty list, and an if at the end filters the items. Comprehensions are the usual way to build a list from another one in Python.
Key facts
[n * n for n in range(5)]builds[0, 1, 4, 9, 16]in one expression, the same list a for loop withappend()would build.- The parts are an expression, a
forclause and an optionaliffilter, in that order. - An
ifafter theforkeeps or drops items. Anif ... elsebefore theforchanges them. - Two
forclauses run like nested loops, with the first one outer. - A comprehension always builds a new list and leaves the source unchanged.
What is list comprehension in Python?
A list comprehension builds a new list from an iterable in one expression inside square brackets. It does the job of a for loop that starts with an empty list and appends one value per pass, and it reads as a description of the list rather than as instructions for building it.
squares = []
for n in range(1, 6):
squares.append(n * n)
print(squares)
squares = [n * n for n in range(1, 6)]
print(squares)[1, 4, 9, 16, 25] [1, 4, 9, 16, 25]
Both versions print the same list. The loop version needs three lines, a variable to hold the result and an append() call on every pass. The comprehension names the value to keep, n * n, then the loop that supplies n, and Python builds the list in one go.
What is the syntax of a list comprehension?
The form is [expression for item in iterable], with an optional if condition at the end. The expression says what goes into the new list, the for clause names each item and where the items come from, and the condition, when present, decides which items are kept.
| Part | Example | What it does |
|---|---|---|
| Expression | price * 2 | The value stored for each item, which can be the item itself |
| for clause | for price in prices | The loop variable and the iterable, written like a for loop header without the colon |
| if clause | if price > 5 | Optional, keeps only the items for which the condition is true |
prices = [4, 10, 25]
doubled = [price * 2 for price in prices]
print(doubled)
print(prices)
names = ["ada", "bob"]
print([name.upper() for name in names])
print([len(name) for name in names])[8, 20, 50] [4, 10, 25] ['ADA', 'BOB'] [3, 3]
The expression can call methods and functions on the item, as name.upper() and len(name) do, and the source list is never changed. The iterable can be anything a for loop accepts, including a string or a range().
How do I add a condition to a list comprehension?
Write if and the condition after the for clause. Items that fail the test are skipped, so the condition works as a filter and the new list can be shorter than the source.
nums = [3, 8, 5, 12, 7]
evens = []
for n in nums:
if n % 2 == 0:
evens.append(n)
print(evens)
print([n for n in nums if n % 2 == 0])
print([n for n in nums if n > 5])[8, 12] [8, 12] [8, 12, 7]
The if at the end takes no else, because it only decides whether an item is kept. Two conditions can be joined with and or or, the same logical operators an if statement uses.
How do I use if and else in a list comprehension?
Put the if and else before the for, as part of the expression. "even" if n % 2 == 0 else "odd" is a conditional expression that picks one of two values, so every item still produces something and the new list has the same length as the source.
nums = [3, 8, 5, 12]
labels = ["even" if n % 2 == 0 else "odd" for n in nums]
print(labels)
capped = [n if n < 10 else 10 for n in nums]
print(capped)
print([n * 2 if n > 5 else n for n in nums if n != 3])['odd', 'even', 'odd', 'even'] [3, 8, 5, 10] [16, 5, 24]
The position is the whole rule. An if before the for changes items and needs an else, and an if after the for drops items and can't have one. The last line uses both, and the filter runs first, so 3 never reaches the expression.
Can a list comprehension have two for loops?
Yes. Write the for clauses one after another in the same order as the nested loops they replace, with the outer loop first. Each item of the first loop is paired with every item of the second.
colors = ["red", "blue"]
sizes = ["S", "M"]
pairs = []
for color in colors:
for size in sizes:
pairs.append(color + " " + size)
print(pairs)
print([color + " " + size for color in colors for size in sizes])
grid = [[1, 2], [3, 4], [5, 6]]
print([n for row in grid for n in row])['red S', 'red M', 'blue S', 'blue M'] ['red S', 'red M', 'blue S', 'blue M'] [1, 2, 3, 4, 5, 6]
The last comprehension flattens a list of lists, and it reads the same way as the loop it replaces, row by row and then item by item. Two for clauses are the sensible limit, because a third makes the line hard to read, and a plain nested loop is the better choice at that point.
Should I use a list comprehension or a for loop?
Use a comprehension when the only job of the loop is building a list. Use a for loop when it does anything else.
A comprehension is the wrong tool for printing. The list it builds would hold nothing but None, because print() returns None, and the printing was the only thing you wanted. A comprehension also can't stop early with break or hold several statements, so a loop body with more than one step belongs in a loop.
| Form | What it does | Use it when |
|---|---|---|
| List comprehension | Builds a new list from one expression, in one line | The result is a list and the expression fits on one line |
| for loop | Runs any statements once per item | The body prints, updates other variables, needs break or continue, or has several steps |
Speed is not the reason to choose. A comprehension is often a little faster than the equivalent loop, because Python skips the repeated append() call, but the difference is small for everyday lists and readability decides.
Common mistakes with list comprehensions in Python
These four mistakes with list comprehensions are the common ones. Two are syntax errors that Python reports at once, and two produce code that runs but is wrong or hard to read.
- SyntaxError: expected 'else' after 'if' expression. An
ifwas placed before theforwithout anelse. Move it after theforto filter, or add theelseto choose a value. - SyntaxError: invalid syntax. An
elsefollowed the filter at the end. The filter takes noelse, so move the wholeif ... elsebefore thefor. - Forgetting the square brackets.
squares = (n * n for n in nums)with parentheses creates a generator, not a list. A generator is a different kind of value, and for now the thing to know is that printing one shows<generator object ...>instead of the numbers. Use square brackets for a list. - Cramming too much in. A comprehension with two conditions, an if/else and two for clauses is valid Python and unreadable. Split it into a loop.
Run the two broken programs to see the messages, then fix them in the editor.
nums = [3, -1, 4]
print([n if n > 0 for n in nums]) File "main.py", line 2
print([n if n > 0 for n in nums])
^^^^^^^^^^
SyntaxError: expected 'else' after 'if' expressionnums = [3, -1, 4]
print([n for n in nums if n > 0 else 0]) File "main.py", line 2
print([n for n in nums if n > 0 else 0])
^^^^
SyntaxError: invalid syntaxExercise
Complete the comprehension so it keeps only the words longer than four letters and converts each one to uppercase with upper(), printing ['APPLE', 'BANANA']. The starter copies every word unchanged.
words = ["apple", "kiwi", "banana", "fig"]
long_words = [word for word in words]
print(long_words)
['APPLE', 'BANANA']
Show the solution
words = ["apple", "kiwi", "banana", "fig"]
long_words = [word.upper() for word in words if len(word) > 4]
print(long_words)
Quiz
This quiz has 5 questions. Pick an answer to see why it is right or wrong.
-
1What does this program print?
print([x * 2 for x in [1, 2, 3]])The expression x * 2 is evaluated once per item, giving 2, 4 and 6. A comprehension never repeats the source list, which is what the separate operator [1, 2, 3] * 2 would do.
-
2What does this program print?
print([x for x in range(6) if x % 2 == 0])range(6) gives 0 to 5, and the filter keeps the even ones, so 0, 2 and 4 remain. The 6 is never produced, because the stop value is left out.
-
3Which comprehension is written correctly?
An if with an else belongs before the for, as a conditional expression. An if after the for is a filter and cannot take an else, and a comprehension has no colon.
-
4What does this program print?
print(len([a + b for a in "xy" for b in "12"]))Two for clauses pair every item of the first with every item of the second, so two letters times two digits gives four strings. The comprehension itself is valid Python.
-
5What does the if at the end of [n for n in nums if n > 0] do?
An if after the for is a filter, so items that fail the test are left out of the new list. Replacing values needs an if and else before the for, and a comprehension never stops early.