List Comprehensions in Python
List comprehensions give you a concise way to create lists from existing iterables. They replace multi-line for loops with a single readable expression. If you’ve ever found yourself writing for loops that just append to a list, comprehensions can simplify your code.
Basic Syntax
A list comprehension has three parts: the expression (what you want in the new list), the iteration (what you’re looping over), and an optional condition (what to filter by).
# Traditional for loop
squares = []
for x in range(10):
squares.append(x ** 2)
# List comprehension — same result
squares = [x ** 2 for x in range(10)]
print(squares)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
The comprehension reads left to right: “x squared, for each x in range(10).” This pattern comes directly from mathematical set-builder notation, which is why Python uses square brackets—the result is a list.
You can use any expression as the output, not just math operations:
words = ["hello", "world", "python"]
uppercased = [word.upper() for word in words]
print(uppercased)
# ['HELLO', 'WORLD', 'PYTHON']
Filtering with Conditions
Add an if clause to filter which items are included in the resulting list. The condition goes after the iteration:
# Only even numbers
evens = [x for x in range(20) if x % 2 == 0]
print(evens)
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# Strings longer than 3 characters
words = ["hi", "hello", "hey", "greetings", "yo"]
long_words = [w for w in words if len(w) > 3]
print(long_words)
# ['hello', 'greetings']
You can combine filtering with transformation in a single comprehension. This is one of the most common patterns:
# Get the lengths of words that start with 'a'
words = ["apple", "banana", "apricot", "blueberry", "avocado"]
a_word_lengths = [len(w) for w in words if w.startswith('a')]
print(a_word_lengths)
# [5, 7, 7]
Transforming Data
Comprehensions shine when you need to apply the same transformation to every element. This is cleaner than a manual loop:
names = ["alice", "bob", "charlie"]
capitalized = [name.capitalize() for name in names]
print(capitalized)
# ['Alice', 'Bob', 'Charlie']
# Convert Celsius to Fahrenheit
celsius = [0, 20, 37, 100]
fahrenheit = [(c * 9/5) + 32 for c in celsius]
print(fahrenheit)
# [32.0, 68.0, 98.6, 212.0]
You can also call methods, use functions, or build complex expressions:
import math
# Calculate square roots
numbers = [16, 25, 36, 49]
roots = [math.sqrt(n) for n in numbers]
print(roots)
# [4.0, 5.0, 6.0, 7.0]
# Parse strings to integers
string_numbers = ["10", "20", "30"]
integers = [int(s) for s in string_numbers]
print(integers)
# [10, 20, 30]
Nested Loops
You can nest loops inside a comprehension. The outer loop comes first:
# Flatten a matrix
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [num for row in matrix for num in row]
print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
This reads as: “for each row in matrix, for each num in row, include num.”
You can also create Cartesian products—every combination of items from both iterables:
# All pairs of colors and sizes
colors = ["red", "blue"]
sizes = ["S", "M", "L"]
combinations = [(color, size) for color in colors for size in sizes]
print(combinations)
# [('red', 'S'), ('red', 'M'), ('red', 'L'), ('blue', 'S'), ('blue', 'M'), ('blue', 'L')]
Dict and Set Comprehensions
The same syntax works for dictionaries and sets. Just use curly braces:
# Dict comprehension: create a name-to-length mapping
names = ["alice", "bob", "charlie"]
name_lengths = {name: len(name) for name in names}
print(name_lengths)
# {'alice': 5, 'bob': 3, 'charlie': 7}
# Set comprehension: get unique lengths
words = ["cat", "dog", "bird", "cat", "dog"]
unique_lengths = {len(w) for w in words}
print(unique_lengths)
# {3, 4}
Set comprehensions automatically remove duplicates since sets only hold unique values.
When to Use List Comprehensions
Use list comprehensions when:
- You need to transform or filter a list in a simple, readable way
- The logic fits on a single line without becoming hard to read
- You want slightly better performance than a for loop with
.append()
Use a regular for loop when:
- The body contains multiple statements or side effects
- The logic is complex enough that a comprehension would be unreadable
- You need to handle exceptions during iteration
- You are building something other than a list (use a generator expression instead)
Here’s an example where a for loop is clearer:
# Don't do this — too hard to read
results = [process(f(x)) for x in items if validate(x)]
# Do this instead — much clearer
results = []
for x in items:
if validate(x):
result = process(f(x))
results.append(result)
Readability matters more than brevity. A comprehension that spans three lines is usually too long.
Generator Expressions
If you don’t actually need a list, use a generator expression instead. It produces values lazily, one at a time, rather than building the entire list in memory:
# List comprehension — creates entire list in memory
squares = [x**2 for x in range(1000000)]
# Generator expression — yields one at a time
squares_gen = (x**2 for x in range(1000000))
Generator expressions use parentheses instead of square brackets. They’re useful when you’re passing an iterable to a function like sum() or max():
# Sum of squares — generator is more memory efficient
total = sum(x**2 for x in range(1000000))
Conclusion
List comprehensions are one of Python’s most beloved features. They let you express common patterns—filtering, transforming, flattening—in a single readable line. Use them for simple operations, but switch to explicit loops when the logic gets complex. Your future self (and anyone reading your code) will thank you.
Next Steps
Now that you understand list comprehensions, explore these related topics:
- Dictionary comprehensions — build dicts with the same syntax
- Generator expressions — lazy evaluation for large datasets
- The map() and filter() functions — functional alternatives to comprehensions
- Set comprehensions — when you need unique values only