What Is a List Comprehension?
A list comprehension is a concise way to create a list from an iterable, combining a loop and optionally a condition into a single readable expression.
Basic syntax:
[expression for item in iterable]
[expression for item in iterable if condition]
Compare the two approaches:
# Traditional loop
squares = []
for n in range(10):
squares.append(n ** 2)
# List comprehension
squares = [n ** 2 for n in range(10)]
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Same result, half the lines, more readable.
Basic Examples
Square numbers:
squares = [x ** 2 for x in range(1, 6)]
# [1, 4, 9, 16, 25]
Convert to uppercase:
fruits = ["apple", "banana", "cherry"]
upper = [f.upper() for f in fruits]
# ["APPLE", "BANANA", "CHERRY"]
Extract attribute from objects:
users = [{"name": "Alice", "age": 28}, {"name": "Bob", "age": 34}]
names = [u["name"] for u in users]
# ["Alice", "Bob"]
Adding a Condition (Filtering)
Add if at the end to filter elements:
# Only even numbers
evens = [n for n in range(20) if n % 2 == 0]
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# Words longer than 4 characters
words = ["cat", "elephant", "dog", "rhinoceros", "ox"]
long_words = [w for w in words if len(w) > 4]
# ["elephant", "rhinoceros"]
# Filter out None values
values = [1, None, 3, None, 5]
clean = [v for v in values if v is not None]
# [1, 3, 5]
if-else in the Expression
The if-else can go before the for to transform (not filter) elements:
# Label even/odd
labels = ["even" if n % 2 == 0 else "odd" for n in range(6)]
# ["even", "odd", "even", "odd", "even", "odd"]
# Clamp negatives to 0
nums = [-3, 5, -1, 8, -2, 4]
clamped = [n if n > 0 else 0 for n in nums]
# [0, 5, 0, 8, 0, 4]
Nested List Comprehensions
Flatten a 2D list:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [n for row in matrix for n in row]
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
Transpose a matrix:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
transposed = [[row[i] for row in matrix] for i in range(3)]
# [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Nested comprehensions quickly become hard to read. If you need three levels of nesting, use a regular loop.
Dictionary Comprehensions
Same syntax, with {} and key: value:
# Square each number
squares = {n: n ** 2 for n in range(1, 6)}
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# Invert a dictionary
original = {"a": 1, "b": 2, "c": 3}
inverted = {v: k for k, v in original.items()}
# {1: "a", 2: "b", 3: "c"}
# Filter a dict
prices = {"apple": 0.5, "truffle": 120.0, "milk": 1.2}
affordable = {k: v for k, v in prices.items() if v < 10}
# {"apple": 0.5, "milk": 1.2}
Set Comprehensions
Use {} without key-value pairs for a set (deduplicates automatically):
nums = [1, 2, 2, 3, 3, 3, 4]
unique_squares = {n ** 2 for n in nums}
# {1, 4, 9, 16}
Generator Expressions
Replace [] with () to get a lazy generator instead of a full list in memory:
# List comprehension — builds full list in memory
total = sum([n ** 2 for n in range(1_000_000)])
# Generator expression — computes one at a time, much less memory
total = sum(n ** 2 for n in range(1_000_000))
When passing to a function that accepts an iterable (sum, max, any, all), use a generator expression.
Real-World Examples
Parse CSV-like data:
raw = ["Alice,28,Engineer", "Bob,34,Designer", "Carol,22,Developer"]
people = [line.split(",") for line in raw]
# [["Alice", "28", "Engineer"], ...]
people_dicts = [
{"name": p[0], "age": int(p[1]), "role": p[2]}
for p in people
]
Find all .py files:
import os
py_files = [f for f in os.listdir(".") if f.endswith(".py")]
Unique words in text:
text = "the cat sat on the mat the cat"
unique_words = list({word for word in text.split()})
When NOT to Use List Comprehensions
Comprehensions are for simple, readable transformations. Avoid them when:
- The logic requires multiple statements — use a regular loop
- Side effects are involved — printing, writing to files, modifying external state
- It spans more than 2 lines — readability drops sharply
- Nested 3+ levels deep — always reach for a regular loop
# Too complex — just use a loop
result = [
process(item)
for sublist in data
for item in sublist
if item.is_valid()
if not item.is_archived()
]
Performance
List comprehensions are generally faster than equivalent for loops with append because Python optimizes them internally. But the difference is small and shouldn't be the reason you use them — readability is the real benefit.
Conclusion
List comprehensions are one of Python's most distinctive and practical features. They shine for transformations, filtering, and simple reshaping of data. The rule of thumb: if you can read it out loud naturally in one sentence, a comprehension is appropriate. If you're squinting at it, write a loop.