PythonList Comprehensions

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.

Python
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.

Python
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']
Note
You can also put a conditional *expression* (an inline if/else) before the `for` clause, e.g. `[x if x % 2 == 0 else -x for x in numbers]`. That is a different feature from the filtering `if` shown above — the ternary form always produces one output item per input item, it just changes what that item is, while a trailing `if` clause can drop items.
For-Loop vs. Comprehension

Here is the same task written both ways, so you can see exactly how the loop maps onto the comprehension.

Python
# --- 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.

Python
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.

Python
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]]
Warning
It is tempting to cram multiple `for` and `if` clauses into one line, but deeply nested comprehensions quickly become unreadable. If you find yourself writing something like `[f(x, y) for x in xs if cond1(x) for y in ys if cond2(x, y)]`, stop and consider a regular `for` loop, a helper function, or breaking the work into two comprehensions instead. Readability counts more than saving a few lines.
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 .append attribute 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 for statement.

Python
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.
Note
The performance gap is a nice bonus, not the main reason to prefer comprehensions. The bigger win is expressing "build a list like this" as a single, declarative expression instead of several imperative statements.