List comprehensions
What you'll learn:
- build a new list from an old one in a single line—with a list comprehension;
- pick elements with an
iffilter and tell it apart from a conditional expression; - build dicts and sets with comprehensions;
- compute a sum, a minimum and a maximum without an extra list—with a generator expression.

Picture a conveyor in a factory. Tiles with the numbers 1, 2, 3, 4 ride along the belt one after another. On the way stands a press labeled n * n: it stamps each tile with the square of its number. At the end of the belt, the tiles 1, 4, 9, 16 drop into a box—in the same order they rode in.
Programs do this kind of work all the time. They take each element of a list, do something with it and put the results into a new list. You already know how to do it with a loop and append. Compare that loop with one line that does the same thing:
nums = [1, 2, 3, 4]
squares = []
for n in nums:
squares.append(n * n)
print(squares) # [1, 4, 9, 16]
squares = [n * n for n in nums]
print(squares) # [1, 4, 9, 16]Let's go through both versions:
- The loop creates an empty list
squares, loops overnumsand for eachnaddsn * nwithappend. - The line
[n * n for n in nums]does the same work by itself: it loops overnumsand collects the squares into a new list. - Both versions print
[1, 4, 9, 16].
The form [n * n for n in nums] is called a list comprehension. It reads almost like a phrase: "n * n for each n in nums". It has no empty list and no append, and the name squares appears once.
How a comprehension works
A comprehension mirrors the conveyor. Inside the square brackets there are two parts:
- first an expression—the press that turns an element into a new value;
- then a
forloop header without a colon—the belt that feeds the elements one at a time.
Python loops over nums, computes the expression for each element and puts the results into a new list in order. This is where the analogy stops working: a real press changes the tile itself, while the original list nums stays as it was. A comprehension builds a new list next to the old one.
A comprehension is an expression, like the conditional expression. You can assign it to a variable, pass it to print or put it after return. You can loop over any iterable—a list, a string, a range:
print([c.upper() for c in "abc"]) # ['A', 'B', 'C']
print([i * 10 for i in range(4)]) # [0, 10, 20, 30]
print([len(w) for w in ["ox", "sun"]]) # [2, 3]The filter condition
You can put an inspector in front of the press: it lets only suitable tiles through. In a comprehension, an if with a condition after the for header plays this role. Only the elements for which the condition is true get into the result:
nums = [4, -1, 7, 0, -3]
print([n * 2 for n in nums if n > 0]) # [8, 14]
print([n if n > 0 else 0 for n in nums]) # [4, 0, 7, 0, 0]Let's go through the first line:
for n in numsfeeds the numbers one at a time:4,-1,7,0,-3.if n > 0lets only4and7through.- The expression
n * 2is computed only for them, and8and14get into the list.
An element that fails the test drops out entirely, so the result is shorter than the original list. Such a comprehension replaces a loop in which append sits inside an if.
The second line has no filter: the place of the expression holds the conditional expression n if n > 0 else 0. It picks a value for each element, so the list keeps its length. Every non-positive number becomes 0 instead of being dropped.
A loop inside out
The most unusual thing about a comprehension is its order. You read it from left to right, but it runs in a different order:
- First,
fortakes the next element. - Then
ifdecides whether to keep it. - The expression on the left is computed last, and its value is added to the list.
A comprehension is a loop with append, turned inside out. What sits deepest in the loop, append(n * 2), comes first in the comprehension. Press "Next step" and watch the order in which the lines of the loop run. The comprehension on the last line goes through the same steps.
1nums = [4, -1, 7]2result = []3for n in nums:4 if n > 0:5 result.append(n * 2)6print(result)7print([n * 2 for n in nums if n > 0])
The list nums is a belt with three tiles.
A comprehension differs from a loop in one more way: its variable lives only inside the brackets. After the loop for x in nums, the name x stays, holding the last element. After [x * 2 for x in nums], there is no x outside, and print(x) raises a NameError. Interviewers like to ask this.
Two for clauses
A comprehension can hold several for headers in a row. They nest in the same order as ordinary loops:
- the first
foris the outer one; - the second
foris the inner one, and it can loop over the variable of the outer one.
So [ch for w in ["ab", "cd"] for ch in w] gives ['a', 'b', 'c', 'd']. The outer loop takes a word, and the inner one takes its letters. This is the same result as a loop for w in … in which a loop for ch in w adds ch with append.
The order of the headers is the reverse of the phrase "letters of each word". In [ch for ch in w for w in words], the name w does not exist yet, and Python raises a NameError. When one line holds two for clauses and a condition, ordinary nested loops are clearer.
Common mistake
The filter is written before for, like a conditional expression without else:
nums = [4, -1, 7, 0, -3]
positive = [n if n > 0 for n in nums] # ✗SyntaxError: expected 'else' after 'if' expressionBefore for, Python expects an expression, and n if n > 0 without else is not one, so the file does not run. A condition that drops elements goes after the loop header: [n for n in nums if n > 0].
Key points
- The list comprehension
[n * n for n in nums]builds a new list and leaves the original unchanged. - An
iffilter stands afterforand drops elements; a conditional expression withelsestands beforeforand keeps the length. - A comprehension is a loop with
appendturned inside out:forfirst, thenif, the expression on the left last. - Several
forclauses nest in the order they are written: the first is the outer one.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.