What Are List Comprehensions?
List comprehensions are one of Python's most distinctive and powerful features. They let you create lists using a compact, readable expression — replacing multi-line for loops with a single, expressive line. Once you get comfortable with them, you'll find yourself reaching for them constantly.
Basic Syntax
The general form of a list comprehension is:
[expression for item in iterable]
Compare the two approaches below:
# Traditional loop
squares = []
for n in range(10):
squares.append(n ** 2)
# List comprehension
squares = [n ** 2 for n in range(10)]
Both produce [0, 1, 4, 9, 16, 25, 36, 49, 64, 81], but the comprehension is more concise and — once you read it fluently — clearer in intent.
Adding Conditions (Filtering)
You can add an optional if clause to filter items:
# Only even squares
even_squares = [n ** 2 for n in range(10) if n % 2 == 0]
# → [0, 4, 16, 36, 64]
This replaces a loop with both an append and an if statement, cutting boilerplate in half.
Nested List Comprehensions
You can nest comprehensions to work with multi-dimensional data:
# Flatten a 2D matrix
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [val for row in matrix for val in row]
# → [1, 2, 3, 4, 5, 6, 7, 8, 9]
Read nested comprehensions left to right — the outer loop comes first, the inner loop second, just as they would in a traditional nested for loop.
Dictionary and Set Comprehensions
The same pattern extends to other data structures:
# Dictionary comprehension
word_lengths = {word: len(word) for word in ["hello", "world", "python"]}
# → {'hello': 5, 'world': 5, 'python': 6}
# Set comprehension (removes duplicates automatically)
unique_remainders = {n % 5 for n in range(20)}
When to Use Them — and When Not To
- Use comprehensions when the logic is simple and the intent is clear at a glance.
- Avoid comprehensions when the expression becomes long or requires multiple nested conditions — readability suffers fast.
- Never use them for side effects. If your loop body calls a function for its side effect (printing, writing to a file), a regular
forloop is more honest about intent.
Performance Considerations
List comprehensions are generally faster than equivalent for loops in CPython because the list-building machinery runs closer to C-speed. However, if you only need to iterate (not store) the result, a generator expression is more memory-efficient:
# Generator — doesn't build the list in memory
total = sum(n ** 2 for n in range(1_000_000))
Quick Reference
| Pattern | Syntax |
|---|---|
| Basic | [expr for x in iterable] |
| Filtered | [expr for x in iterable if cond] |
| Nested | [expr for x in a for y in b] |
| Dict | {k: v for k, v in pairs} |
| Set | {expr for x in iterable} |
| Generator | (expr for x in iterable) |
Conclusion
List comprehensions are a hallmark of idiomatic Python. Start with simple cases, keep expressions readable, and gradually tackle filtered and nested forms. Your code will become more expressive — and often faster — as a result.