Article
Python list comprehensions: when to use them (and not)
List comprehensions turn a four-line loop into one readable line, until they don't. Learn the pattern, the filter form, and the point where a plain loop wins.
On this page0%
- The loop you already know
- The pattern
- Add a filter with if
- If/else goes in front, not at the end
- Real examples worth knowing
- Dictionary and set versions
- When a comprehension is the wrong tool
- A simple rule of thumb
- Common mistakes
- FAQ
- What is a list comprehension in Python?
- Are list comprehensions faster than for loops?
- Can I use if and else in a list comprehension?
- What is the difference between a list comprehension and a generator expression?
- Next reading on Sythra Articles
Sooner or later you read someone's Python and meet a line like this:
squares = [n * n for n in range(10)]
That is a list comprehensionA one-line way to build a new list by transforming or filtering another sequence. It does exactly what a short for loop does, in a more compact shape. This guide shows how to read one, how to write one, and — just as important — when to leave them alone.
The loop you already know
Start with a loop that builds a list:
squares = []
for n in range(10):
squares.append(n * n)
print(squares)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Three things happen: make an empty list, loop, append each result. A comprehension collapses all three.
The pattern
[expression for item in iterable]
Read it left to right as a sentence: "give me expression, for each item in iterable."
names = ["ada", "grace", "linus"]
upper = [name.upper() for name in names]
print(upper) # ['ADA', 'GRACE', 'LINUS']
The part before for is what goes into the new list. The part after it is the loop. Nothing else is hidden.
Add a filter with if
Put an if at the end to keep only some items:
numbers = [3, 8, 1, 12, 7, 20]
big = [n for n in numbers if n > 5]
print(big) # [8, 12, 7, 20]
The loop version is:
big = []
for n in numbers:
if n > 5:
big.append(n)
You can transform and filter together:
words = ["Python", "is", "a", "language"]
lengths = [len(w) for w in words if len(w) > 2]
print(lengths) # [6, 8]
If/else goes in front, not at the end
This is the part that trips beginners. A filter if goes after the loop. An if/else that chooses between two values goes before it, because it is part of the expression:
scores = [45, 82, 67, 91]
labels = ["pass" if s >= 60 else "fail" for s in scores]
print(labels) # ['fail', 'pass', 'pass', 'pass']
Memory trick: if there is an else, the whole a if cond else b is the expression, so it sits first.
Real examples worth knowing
Clean up text read from a file:
lines = [" hello \n", "world\n", " \n"]
clean = [line.strip() for line in lines if line.strip()]
print(clean) # ['hello', 'world']
Pull one field out of a list of dictionaries:
users = [
{"name": "Ada", "age": 36},
{"name": "Grace", "age": 45},
]
names = [u["name"] for u in users]
print(names) # ['Ada', 'Grace']
Flatten a nested list with two loops (read the for parts in the same order you would write nested loops):
grid = [[1, 2], [3, 4], [5, 6]]
flat = [x for row in grid for x in row]
print(flat) # [1, 2, 3, 4, 5, 6]
Dictionary and set versions
The same idea works for dictionaries and sets using braces:
word_lengths = {w: len(w) for w in ["apple", "fig", "banana"]}
print(word_lengths) # {'apple': 5, 'fig': 3, 'banana': 6}
unique_lengths = {len(w) for w in ["apple", "fig", "pear"]}
print(unique_lengths) # {3, 4, 5}
When a comprehension is the wrong tool
Comprehensions are for building a collection. They get worse the moment you stretch them.
Too much logic. If you need a nested if inside a nested for with a function call, a loop is easier to read and debug:
# Hard to scan
result = [transform(x) for row in data for x in row if x is not None and x > 0 and valid(x)]
# Easier
result = []
for row in data:
for x in row:
if x is None or x <= 0 or not valid(x):
continue
result.append(transform(x))
Side effects. Do not use a comprehension just to run something. This builds a throwaway list of None values:
[print(n) for n in range(3)] # works, but misleading
for n in range(3): # say what you mean
print(n)
Huge data you only loop over once. A comprehension builds the entire list in memory. If you only need to iterate, use a generator expressionLike a list comprehension in parentheses; produces items one at a time instead of storing them all:
total = sum(n * n for n in range(1_000_000))
No brackets, no million-item list.
A simple rule of thumb
- One transformation, maybe one filter, fits on one line → comprehension
- You need to explain it with a comment → loop
- You are not building a list → loop
Readable beats clever. A teammate (or you in three months) should understand the line without pausing.
Common mistakes
- Putting
elseat the end.[x for x in items if x else 0]is a syntax error. Move the conditional to the front. - Forgetting the loop variable leaks nowhere. In Python 3 the variable inside a comprehension does not exist afterwards, unlike a normal
forloop. - Modifying the list you are looping over. Build a new list instead; that is what comprehensions are for.
FAQ
What is a list comprehension in Python?
A list comprehension is a compact syntax for creating a list from another sequence: [expression for item in iterable if condition]. It replaces a loop that creates an empty list and appends to it.
Are list comprehensions faster than for loops?
Usually a little faster, because the append work happens in optimised internals. The difference rarely matters; choose based on readability first.
Can I use if and else in a list comprehension?
Yes. Put the if/else before the for: ["yes" if n > 0 else "no" for n in numbers]. A plain filter if goes after the for.
What is the difference between a list comprehension and a generator expression?
A list comprehension builds the whole list in memory immediately. A generator expression uses parentheses and produces values one at a time, which saves memory when you only iterate once.