In a Python list comprehension, if else goes before the for, and a bare if goes after it. Get that backwards and Python raises a SyntaxError.
labels = ["pass" if s >= 50 else "fail" for s in scores] # if/else before the for
passed = [s for s in scores if s >= 50] # bare if after the for
The first one labels every item. The second one throws items away. That single difference is what most of the questions about this are really about.
I ran each snippet on Python 3.12.5 and screenshotted the Command Prompt, so the output you see is the output I got.
Where if else goes in a list comprehension
Those are two different pieces of syntax that happen to share a keyword.
"pass" if s >= 50 else "fail" is a conditional expression. It’s a value, so it belongs where a value belongs: at the front, where the comprehension decides what to put in the list.
The trailing if s >= 50 is a filter clause. It’s part of the loop, so it sits with the loop, after the for.
scores = [92, 45, 78, 61, 30]
# if/else goes BEFORE the for: every score produces a value
labels = ["pass" if s >= 50 else "fail" for s in scores]
print(labels)
# a bare if goes AFTER the for: it filters, so the list gets shorter
passed = [s for s in scores if s >= 50]
print(passed)
print("in:", len(scores), "| labelled:", len(labels), "| filtered:", len(passed))
Output:
['pass', 'fail', 'pass', 'pass', 'fail']
[92, 78, 61]
in: 5 | labelled: 5 | filtered: 3
Count the outputs and the rule stops being abstract. The conditional expression kept the length at five. The filter cut it to three.
| What you want | Where the condition goes | Example |
|---|---|---|
| A value for every item | Before the for | [a if cond else b for x in xs] |
| Only some items | After the for | [x for x in xs if cond] |
| Both | Both places | [a if c1 else b for x in xs if c2] |
| More than two outcomes | Chain, or call a function | [f(x) for x in xs] |
Why your if else gives a SyntaxError
Put the else after the for and Python stops before it runs a single line:
scores = [92, 45, 78, 61, 30]
# the same if/else, but placed after the for
labels = [s for s in scores if s >= 50 else "fail"]
print(labels)
What Python says:
File "C:\pyguides\list_comp_syntax_error.py", line 4
labels = [s for s in scores if s >= 50 else "fail"]
^^^^
SyntaxError: invalid syntax
else, because nothing is allowed there.The filter clause has no else branch to offer. Python has already finished reading a valid comprehension by the time it meets that word, so it has nowhere to put it.
The fix is always the same: decide whether you’re labelling or filtering, then move the condition to the matching end.
List comprehension if with no else (“do nothing”)
This is the most common follow-up, and the short answer is that you can’t. A conditional expression must produce a value, so the else is not optional.
What you actually want is the filter form:
values = [4, -2, 9, -7, 0]
# there is no "and otherwise do nothing" in a conditional expression.
# dropping the else is a SyntaxError, so move the test after the for instead:
kept = [v for v in values if v > 0]
print(kept)
# if you want a placeholder rather than a shorter list, say so out loud
marked = [v if v > 0 else None for v in values]
print(marked)
print([v for v in marked if v is not None])
Output:
[4, 9]
[4, None, 9, None, None]
[4, 9]
If you’d rather keep the positions and mark the gaps, put something explicit in the else and strip it afterwards. That’s the second half of the output above.
Filter and transform in one list comprehension
Both conditions can appear in the same comprehension, and this is where the order finally pays off:
readings = [12.4, None, -3.0, 40.1, None, 8.0]
# filter with the if after the for, transform with the if/else before it
cleaned = [round(r) if r > 0 else 0 for r in readings if r is not None]
print(cleaned)
# read it in the order Python runs it:
# for r in readings -> if r is not None -> round(r) if r > 0 else 0
print(len(readings), "readings in,", len(cleaned), "out")
Output:
[12, 0, 40, 8]
6 readings in, 4 out
Nones were filtered, the rest were transformed.Read it in the order Python runs it, not the order you see it: the for first, then the filter, then the expression. Dropping None before doing arithmetic is the usual reason to bother, and it pairs with checking whether a variable is None.
Chaining if else for more than two outcomes
There’s no elif in a comprehension. You chain conditional expressions, and each else holds the next test:
scores = [92, 74, 58, 31]
# there is no elif in a comprehension: you chain conditional expressions
grades = ["A" if s >= 90 else "B" if s >= 70 else "C" if s >= 50 else "F" for s in scores]
print(grades)
# the same thing, but you can read it and test it
def grade(score):
if score >= 90:
return "A"
if score >= 70:
return "B"
if score >= 50:
return "C"
return "F"
print([grade(s) for s in scores])
Output:
['A', 'B', 'C', 'F']
['A', 'B', 'C', 'F']
Three branches is where I’d stop. The chained version and the function below it produce the same grades, but only one of them can be read at a glance or unit-tested on its own.
Once the logic needs a name, give it one. A named function inside the comprehension keeps the line short and the intent obvious, which is the same reason a sort key gets pulled into its own function.
Is a list comprehension faster than a for loop?
A little, and for the usual reason: the comprehension builds the list in C instead of calling append twenty thousand times.
import timeit
setup = "scores = list(range(20_000))"
comp = "[s if s % 2 else -s for s in scores]"
loop = """
out = []
for s in scores:
out.append(s if s % 2 else -s)
"""
for name, stmt in (("comprehension", comp), ("for loop + append", loop)):
ms = timeit.timeit(stmt, setup, number=200) / 200 * 1000
print(f"{name:<18} {ms:6.2f} ms per run")
Output:
comprehension 0.58 ms per run
for loop + append 0.67 ms per run
That gap is real but small. Pick the comprehension because it reads better on one line, not because of the milliseconds.
When not to use a list comprehension
A comprehension stops paying for itself the moment you have to re-read it.
- The condition needs
try/except, which a comprehension can’t hold. - You’re chaining more than two or three conditional expressions.
- The line runs past the edge of the screen and wraps.
- You’re doing something rather than building something, like printing or writing to a file.
A plain for loop is not a lesser tool. It’s the right one whenever the logic is worth a few extra lines, and it handles the cases a lambda inside a comprehension would only make denser.
If you’re working through comprehensions, these go well next:
- Lambda in list comprehension in Python
- Check if a variable is None in Python
- Find the maximum value in an array in Python
- Sort a Python dictionary
- Round numbers to 2 decimal places in Python
Frequently asked questions
Where does if else go in a Python list comprehension?
Before the for. It’s a conditional expression, so it sits where the value goes: [a if cond else b for x in xs]. The Python tutorial on list comprehensions sets out the same grammar.
Why does my list comprehension if else give a SyntaxError?
Because the else is after the for. The filter clause there has no else branch, so move the whole condition to the front.
Can I use if without else in a list comprehension?
Yes, but only as a filter after the for. A conditional expression at the front always needs both branches.
How do I do nothing in the else?
You can’t leave it empty. Either filter with a trailing if, or put a placeholder such as None in the else and remove it later.
Is there an elif in list comprehension?
No. Chain conditional expressions instead, or move the logic into a small function and call it from the comprehension.
Can I use multiple if conditions after the for?
Yes. Several trailing if clauses are combined with and, so [x for x in xs if x > 0 if x % 2] keeps only positive odd numbers.
Is a list comprehension faster than a for loop?
Slightly, because it avoids repeated append calls. The difference is milliseconds on twenty thousand items, so readability should decide.
Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn