Python List Comprehensions — Write Less, Do More
Advertisement
Introduction
Why This Matters
List comprehensions are the most recognizable hallmark of Pythonic code. They allow you to create, filter, and transform lists in a single, readable expression — replacing multi-line for loops with a concise, declarative syntax that is also faster at runtime.
Python's interpreter can optimize list comprehensions through C-level loops, making them meaningfully quicker than equivalent for loops with .append(). In data pipelines, API transformations, and configuration parsing, comprehensions appear constantly. Knowing them well signals Python proficiency in code reviews and technical interviews.
This guide covers list comprehensions from basic patterns to advanced real-world use cases, along with dict and set comprehensions and generator expressions.
Basic List Comprehension
Syntax: [expression for item in iterable if condition]
# Without comprehension
squares = []
for x in range(10):
squares.append(x ** 2)
# With comprehension
squares = [x ** 2 for x in range(10)]
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]Filtering with if
numbers = range(20)
# Only even numbers
evens = [n for n in numbers if n % 2 == 0]
# Numbers divisible by 3 or 5
fizz = [n for n in numbers if n % 3 == 0 or n % 5 == 0]
# Filter non-empty strings
words = ["hello", "", "world", " ", "python"]
clean = [w.strip() for w in words if w.strip()]
# ['hello', 'world', 'python']Transforming Data
# Capitalize names
names = ["alice", "bob", "charlie"]
capitalized = [name.capitalize() for name in names]
# Extract fields from dicts
users = [
{"name": "Alice", "age": 30, "active": True},
{"name": "Bob", "age": 25, "active": False},
{"name": "Charlie", "age": 35, "active": True},
]
active_names = [u["name"] for u in users if u["active"]]
# ['Alice', 'Charlie']
# Type conversion
str_nums = ["1", "2", "3", "4"]
nums = [int(x) for x in str_nums]if/else in Expression (Conditional Transformation)
# Ternary inside comprehension
scores = [85, 62, 91, 45, 78]
grades = ["pass" if s >= 60 else "fail" for s in scores]
# ['pass', 'pass', 'pass', 'fail', 'pass']
# Clamp values
raw = [-5, 3, 150, 50, -1]
clamped = [max(0, min(100, x)) for x in raw]
# [0, 3, 100, 50, 0]Nested Comprehensions
# Flatten a 2D matrix
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [num for row in matrix for num in row]
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Cartesian product
colors = ["red", "blue"]
sizes = ["S", "M", "L"]
variants = [(c, s) for c in colors for s in sizes]
# [('red', 'S'), ('red', 'M'), ('red', 'L'), ('blue', 'S'), ...]
# Transpose matrix
transposed = [[row[i] for row in matrix] for i in range(3)]
# [[1, 4, 7], [2, 5, 8], [3, 6, 9]]Dictionary Comprehensions
# Square map
squares = {x: x**2 for x in range(6)}
# {0: 0, 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()}
# Filter by value
high_scores = {name: s for name, s in {"Alice": 95, "Bob": 60, "Charlie": 80}.items() if s >= 70}
# {'Alice': 95, 'Charlie': 80}
# Build lookup from list
users = [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]
user_by_id = {u["id"]: u["name"] for u in users}Set Comprehensions
# Unique lengths
words = ["hello", "world", "hi", "python", "code"]
lengths = {len(w) for w in words}
# {2, 4, 5, 6}
# Unique domains from emails
emails = ["alice@gmail.com", "bob@yahoo.com", "charlie@gmail.com"]
domains = {e.split("@")[1] for e in emails}
# {'gmail.com', 'yahoo.com'}Generator Expressions
Use when you need to iterate once and don't need to store all values.
# Sum without building a list
total = sum(x ** 2 for x in range(1_000_000))
# First match
first_even = next(x for x in range(100) if x % 2 == 0 and x > 10)
# 12
# Check all/any
all_positive = all(x > 0 for x in [1, 2, 3, 4]) # True
has_negative = any(x < 0 for x in [1, -2, 3]) # TruePerformance: Comprehension vs Loop
import timeit
# Loop approach
def with_loop():
result = []
for i in range(10000):
result.append(i ** 2)
return result
# Comprehension approach
def with_comp():
return [i ** 2 for i in range(10000)]
# Comprehension is typically 20-30% fasterCommon Mistakes
- Using list comprehension when a generator expression is more appropriate (large data)
- Nesting more than two levels — hard to read; use a helper function instead
- Adding side effects inside comprehensions (e.g.,
print()) - Building a full list just to immediately pass to
sum(),all(), orany() - Overcomplicating comprehensions to show off at the expense of readability
Best Practices
- Use comprehensions for simple transformations and filters
- Switch to a regular loop when logic is complex or spans multiple lines
- Prefer generator expressions when you only need to iterate once
- Use
dict[k] = vcomprehension form only when source is another iterable - Limit nesting to two levels maximum; extract inner logic to a named function
Key Takeaways
- List comprehension syntax:
[expr for item in iterable if condition] - Dict comprehension syntax:
{key: value for item in iterable if condition} - Set comprehension syntax:
{expr for item in iterable} - Generator expression syntax:
(expr for item in iterable)— lazy, no list stored - Comprehensions are 20-30% faster than equivalent
for + appendpatterns - Use
any(expr for ...)andall(expr for ...)with generators for short-circuit evaluation - Nested comprehensions are valid but limit to two levels to maintain readability
Advertisement