List Comprehensions
A list comprehension is a compact way to build a new list by transforming and
optionally filtering the items of an existing iterable. Instead of writing a
for loop that repeatedly calls list.append(), you describe the resulting
list in a single expression. Comprehensions are one of the most idiomatic
features of Python — once you get comfortable reading them, most loops
that build a list start to feel unnecessarily verbose.
Basic Syntax
The basic form is [expr for item in iterable]. Python evaluates expr once
for every item produced by iterable, and collects the results into a new
list.
numbers = [1, 2, 3, 4, 5] squares = [n ** 2 for n in numbers] print(squares) # [1, 4, 9, 16, 25] # The iterable can be any iterable, not just a list letters = [c.upper() for c in "python"] print(letters) # ['P', 'Y', 'T', 'H', 'O', 'N']
Adding a Condition
Append an if clause to filter which items get included: [expr for item in iterable if cond]. Items for which cond is falsy are skipped entirely
— they never reach expr.
numbers = range(1, 21) evens = [n for n in numbers if n % 2 == 0] print(evens) # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] # The condition can be arbitrarily complex words = ["apple", "kiwi", "banana", "fig", "grape"] long_words = [w for w in words if len(w) > 4] print(long_words) # ['apple', 'banana', 'grape']
For-Loop vs. Comprehension
Here is the same task written both ways, so you can see exactly how the loop maps onto the comprehension.
# --- Classic for-loop version ---
squares = []
for n in numbers:
if n % 2 == 0:
squares.append(n ** 2)
# --- Equivalent list comprehension ---
squares = [n ** 2 for n in numbers if n % 2 == 0]
# Both produce the same result, but the comprehension states the
# "shape" of the result up front: build a list of n**2 for each
# even n in numbers.Nested Comprehensions
Comprehensions can contain more than one for clause, which is useful for
flattening a nested (2D) structure into a single flat list. The clauses read
left to right in the same order you would nest the equivalent for-loops.
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [value for row in matrix for value in row]
print(flat) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Equivalent nested for-loop:
flat = []
for row in matrix:
for value in row:
flat.append(value)You can also build a new nested list — for example, transposing a
matrix — by nesting one comprehension inside another rather than
chaining for clauses in the same one.
matrix = [[1, 2, 3], [4, 5, 6]] transposed = [[row[i] for row in matrix] for i in range(3)] print(transposed) # [[1, 4], [2, 5], [3, 6]]
Performance: Why Comprehensions Are Fast
List comprehensions are usually noticeably faster than the equivalent
for loop that calls .append() on every iteration. There are two main
reasons:
A comprehension is compiled to specialized bytecode that builds the list directly, whereas a for-loop must repeatedly look up the
.appendattribute on the list object and call it as a function on every single iteration.The comprehension's loop runs in an optimized internal C loop inside the interpreter, avoiding some of the general-purpose overhead of a Python-level
forstatement.
import timeit
def with_loop():
result = []
for n in range(1000):
result.append(n ** 2)
return result
def with_comprehension():
return [n ** 2 for n in range(1000)]
print(timeit.timeit(with_loop, number=1000)) # e.g. ~0.09s
print(timeit.timeit(with_comprehension, number=1000)) # e.g. ~0.06s
# The comprehension is typically 20-40% faster for this kind of work.