Dict Comprehension with If/Else in Python
An if in a dict comprehension can live in two different places, and they do two different jobs: an if at the end filters which items get included, while an x if cond else y expression before the for chooses the value (or key) for every item. Mixing up the two positions is the single most common reason a dict comprehension throws a SyntaxError.
Quick answer: To filter items, put a plain if at the end: {k: v for k, v in d.items() if v > 0}. To pick between two values, put a conditional expression before the for: {k: ("high" if v > 50 else "low") for k, v in d.items()}. A bare if/else at the end is invalid syntax — else only works in the value position.
Where does the filtering if go in a dict comprehension?
The filtering if goes at the very end, after the for clause. It decides whether a key–value pair makes it into the result at all. Items that fail the condition are skipped entirely, so the output dictionary can be smaller than the input. There is no else in this position — filtering is a yes/no decision.
prices = {"apple": 1.20, "banana": 0.50, "cherry": 3.80, "kiwi": 0.90}
# Keep only items priced above 1.00
expensive = {name: price for name, price in prices.items() if price > 1.00}
print(expensive)
# {'apple': 1.2, 'cherry': 3.8}
Trying to bolt an else onto this trailing if fails immediately:
# SyntaxError: invalid syntax
# {name: price for name, price in prices.items() if price > 1.00 else 0}
How do I use if/else for the value in a dict comprehension?
To keep every key but compute a different value depending on a condition, use Python's conditional expression (x if cond else y) in the value slot, before the for. Every input item produces exactly one output item — nothing is filtered out, the value just varies.
prices = {"apple": 1.20, "banana": 0.50, "cherry": 3.80, "kiwi": 0.90}
labels = {name: ("expensive" if price > 1.00 else "cheap")
for name, price in prices.items()}
print(labels)
# {'apple': 'expensive', 'banana': 'cheap', 'cherry': 'expensive', 'kiwi': 'cheap'}
The parentheses around the conditional expression are optional, but they make the two halves of the comprehension much easier to scan. The same trick works on the key side too:
flags = {(name.upper() if price > 1.00 else name): price
for name, price in prices.items()}
print(flags)
# {'APPLE': 1.2, 'banana': 0.5, 'CHERRY': 3.8, 'kiwi': 0.9}
Can I combine both an if/else value and a filtering if?
Yes — they are independent, so you can use both in the same comprehension. The conditional expression before the for picks the value; the trailing if after the for decides whether the item appears at all. Read it as: "for each item that passes the filter, compute this value."
scores = {"amy": 91, "ben": 47, "cara": 78, "dan": None, "eve": 62}
# Skip missing scores, then label the rest
results = {name: ("pass" if s >= 60 else "fail")
for name, s in scores.items()
if s is not None}
print(results)
# {'amy': 'pass', 'ben': 'fail', 'cara': 'pass', 'eve': 'pass'}
Note the evaluation order: the trailing if runs first for each item. That is why the example above never crashes comparing None >= 60 — filtered items never reach the value expression.
Can I chain more than two outcomes with elif?
There is no elif in a conditional expression, but you can nest if/else expressions to get the same effect. Two levels is usually the readable limit; beyond that, use a helper function or a plain loop.
scores = {"amy": 91, "ben": 47, "cara": 78}
grades = {name: ("A" if s >= 90 else "B" if s >= 75 else "C")
for name, s in scores.items()}
print(grades)
# {'amy': 'A', 'ben': 'C', 'cara': 'B'}
# Cleaner for 3+ branches: a helper function
def grade(s):
if s >= 90: return "A"
if s >= 75: return "B"
return "C"
grades = {name: grade(s) for name, s in scores.items()}
When is a dict comprehension with if/else too clever?
A comprehension stops paying for itself once you cannot read it aloud in one breath. If you find yourself nesting three conditions, filtering on multiple clauses, and transforming both the key and the value at once, a plain for loop with a real if/elif/else block is faster to write, easier to debug, and kinder to the next reader.
# Hard to scan:
out = {k.upper() if v else k: (v * 2 if v > 10 else v)
for k, v in data.items() if k.startswith("a") if v is not None}
# The same logic as a loop — longer, but obvious:
out = {}
for k, v in data.items():
if not k.startswith("a") or v is None:
continue
key = k.upper() if v else k
out[key] = v * 2 if v > 10 else v
For the fundamentals of building dictionaries this way — including deduplication and inverting mappings — see our guide to dict comprehensions in Python. The exact same two if positions apply to list comprehensions as well, so learning them once covers both.
Pro Tip: Memorize the rule as "filter at the back, choose at the front." A trailing if can never take an else, and an if/else before the for must always have an else — the two errors are mirror images, and this mnemonic catches both before Python does.