List Comprehension
Learn Python list comprehension syntax, filtering, nested loops, dict and set comprehensions, and when to use them with runnable examples.
Python List Comprehension
List comprehension is a concise way to build a new list by applying an expression to every item in an iterable — optionally filtering items with a condition — all in a single readable line. This page covers the full syntax, common patterns, dict and set comprehensions, and guidance on when a plain for loop is the better choice.
Syntax
The general form of a list comprehension is:
new_list = [expression for item in iterable if condition]| Part | Role |
|---|---|
expression | Value placed in the new list for each item |
item | Loop variable, takes each value from iterable in turn |
iterable | Any sequence or iterable: list, tuple, string, range, etc. |
if condition | Optional filter — only items where the condition is True are included |
The if condition part is optional. When omitted, every item in the iterable produces one entry in the new list.
Basic Example: Squaring Numbers
The equivalent for loop requires three lines; list comprehension does the same in one:
Filtering with a Condition
Add an if clause after the iterable to keep only the items that satisfy a condition:
You can combine any predicate. For example, keeping words that are longer than four characters:
words = ['hi', 'hello', 'world', 'python', 'ai']
long_words = [w for w in words if len(w) > 4]
print(long_words) # ['hello', 'world', 'python']if/else in the Expression (Ternary)
When you need to transform every item but apply different logic depending on a condition, put the if/else inside the expression part (before for), not after the iterable:
numbers = range(1, 6)
labels = ['even' if x % 2 == 0 else 'odd' for x in numbers]
print(labels) # ['odd', 'even', 'odd', 'even', 'odd']Note the difference:
[expr for x in it if cond]— filter: skips items wherecondisFalse[a if cond else b for x in it]— transform: every item produces a value, chosen bycond
Working with Strings
List comprehension works on any iterable, including strings and lists of strings:
words = ['hello', 'world', 'python']
upper_words = [w.upper() for w in words]
print(upper_words) # ['HELLO', 'WORLD', 'PYTHON']Extract individual characters that meet a condition:
vowels = [ch for ch in 'programming' if ch in 'aeiou']
print(vowels) # ['o', 'a', 'i']Nested Loops
List comprehension supports multiple for clauses, equivalent to nested loops. The leftmost for is the outer loop:
A common use case for nested list comprehension is flattening a 2-D list (matrix) into a 1-D list:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [n for row in matrix for n in row]
print(flat) # [1, 2, 3, 4, 5, 6, 7, 8, 9]Reading tip: mentally expand nested comprehensions as nested for loops in the same left-to-right order.
Dictionary Comprehension
The same idea applies to dictionaries using {} with a key: value expression:
keys = ['a', 'b', 'c']
values = [1, 2, 3]
mapping = {k: v for k, v in zip(keys, values)}
print(mapping) # {'a': 1, 'b': 2, 'c': 3}Swap keys and values in an existing dictionary:
original = {'name': 'Alice', 'city': 'Paris'}
inverted = {v: k for k, v in original.items()}
print(inverted) # {'Alice': 'name', 'Paris': 'city'}Set Comprehension
Use {} with a single expression (no colon) to build a set, which automatically removes duplicates:
numbers = [1, 2, 2, 3, 3, 3, 4]
unique_squares = {x ** 2 for x in numbers}
print(unique_squares) # {1, 4, 9, 16}The result is unordered (sets have no guaranteed order), so do not rely on the printed sequence.
Performance
List comprehensions are generally faster than equivalent for loops that call .append() because the interpreter can optimize the internal loop in C. For timing your own code, use the timeit module:
import timeit
loop_time = timeit.timeit(
'result = []\nfor x in range(1000):\n result.append(x**2)',
number=10000
)
comp_time = timeit.timeit(
'[x**2 for x in range(1000)]',
number=10000
)
print(f'Loop: {loop_time:.3f}s')
print(f'Comprehension: {comp_time:.3f}s')
# Comprehension is typically 20-40% fasterPerformance advantage shrinks or disappears when the expression itself is slow (network I/O, heavy computation). Profile before optimizing.
When to Use a Plain for Loop Instead
List comprehension is not always the right tool:
| Situation | Prefer |
|---|---|
| Single transformation or filter | List comprehension |
| Multiple side effects per iteration (logging, mutating state) | for loop |
| Complex logic that needs several statements | for loop |
| Deeply nested comprehensions (more than two levels) | for loop — readability wins |
| The result is never stored (you only need to iterate) | Generator expression ((x for x in ...)) |
The clearest signal to switch back to a for loop is when you find yourself squinting at the comprehension to understand what it does.
Gotchas
Variable leakage does not happen in Python 3. The loop variable in a comprehension is scoped to the comprehension itself:
x = 'original'
result = [x * 2 for x in range(3)]
print(x) # 'original' — not overwritten by the comprehension's xAvoid deeply nested comprehensions. More than two for clauses in a single comprehension hurts readability with little benefit. Break them up into named intermediate lists or for loops.
Generator expressions save memory. If you only need to iterate over the result once (e.g., pass it to sum() or max()), replace [] with () to get a generator that yields items one at a time:
total = sum(x ** 2 for x in range(1, 1001))
print(total) # 333833500