Back to Blog
Python

Python List Comprehension if else: Syntax and Use Cases

python list comprehension if else: Learn how if/else works inside Python list comprehensions: filtering vs transforming values, combining both, and avoiding common syn...

list comprehensionconditional expressionspython syntaxfilteringcode readability
Diagram showing how if/else in a Python list comprehension either filters elements or transforms values, with a list on the the left and a filtered or transformed list on the the right.

The Two Conditional Forms in a List Comprehension

Python list comprehension if else syntax appears in two distinct positions, and confusing them is the most common source of errors. The position of the if keyword determines whether it filters the input sequence or transforms each value.

The filtering form places if after the for clause:

numbers = [1, -2, 3, -4, 5] positive = [n for n in numbers if n > 0] # [1, 3, 5]

Elements that fail the condition are skipped entirely. No else is allowed in this position; the comprehension either keeps an element or drops it.

The transformation form places if/else before the for clause:

numbers = [1, -2, 3, -4, 5] clamped = [n if n > 0 else 0 for n in numbers] # [1, 0, 3, 0, 5]

Here the if/else is a ternary expression evaluated once per element. Every input element produces exactly one output value, and nothing is filtered.

FormPosition of ifBehaviorelse allowed
FilteringAfter forDrops elementsNo
TransformationBefore forChanges valuesYes

The two forms answer different questions. The first asks "which elements should I keep?" The second asks "what value should each element become?"

Filtering Elements With a Trailing if

The trailing if is the the simplest conditional form and the one most developers encounter first. It evaluates a predicate for each element and keeps only those for which the predicate returns a truthy value.

words = ["apple", "", "pear", " ", "plum"] non_empty = [w for w in words if w.strip()] # ["apple", "pear", "plum"]

The strip() call removes surrounding whitespace before the truthiness check, so a string containing only spaces is dropped. This pattern works with any predicate: membership tests, regex matches, type checks, or custom functions.

from pathlib import Path import os files = [Path(p) for p in os.listdir(".")] directories = [f for f in files if f.is_dir()]

Filtering with a trailing if never changes the values that survive; it only removes elements. If you need to keep every element but change some of them, the conditional expression form is the correct tool.

Transforming Values With an if/else Expression

The if/else form behaves like a Python ternary operator applied to every element. It is useful when every element must remain in the result but some need a different value.

scores = [85, 42, 91, 58] passed = [score if score >= 60 else 0 for score in scores] # [85, 0, 91, 0]

The expression score if score >= 60 else 0 is evaluated for each element. This is equivalent to a loop with an if/else block:

passed = [] for score in scores: if score >= 60: passed.append(score) else: passed.append(0)

The comprehension version keeps the decision logic inline and avoids the separate append calls. The ternary expression can also call functions:

users = [{"name": "Ada", "active": true}, {"name": "Bob", "active": false}] status = [u["name"] if u["active"] else f"{u['name']} (inactive)" for u in users]

Combining Filtering and Transformation

Both forms can appear in the same comprehension. The if/else expression comes first, followed by the for clause, followed by the filtering if:

items = [("widget", 3), ("gadget", 0), ("cog", 7)] in_stock = [name.upper() if qty > 5 else name for name, qty in items if qty > 0] # ["widget", "COG"]

The filtering if qty > 0 runs first and removes the "gadget" entry. The ternary name.upper() if qty > 5 else name then transforms the surviving elements. The order matters: filtering happens before transformation, so the ternary never sees elements that the filter removed.

This combination is common when a sequence contains records that must be both validated and normalized in a single pass.

Nested Conditions and elif Equivalents

Python list comprehensions do not support an elif keyword. To express more than two branches, chain ternary expressions:

grades = [92, 74, 58, 81, 39] labels = [ "A" if g >= 90 else "B" if g >= 80 else "C" if g >= 70 else "D" if g >= 60 else "F" for g in grades ] # ["A", "C", "F", "B", "F"]

Each else binds to the nearest preceding if, so the chain evaluates left to right. The formatting above keeps the chain readable, but the expression is still a single ternary nested inside another. For more than three branches, a helper function or a plain loop is usually clearer:

def letter_grade(score): if score >= 90: return "A" if score >= 80: return "B" if score >= 70: return "C" if score >= 60: return "D" return "F" labels = [letter_grade(g) for g in grades]

The comprehension stays readable because the branching logic lives in the function.

Performance and Memory Considerations

A list comprehension builds the entire result list in memory before returning. returns. For large inputs, this can consume significant memory, especially when the transformation creates large objects. A generator expression avoids materializing the list:

total = sum(n if n > 0 else 0 for n in huge_stream)

The generator evaluates lazily, so only one element exists in memory at a time. Use a generator when the result is consumed by a single iteration, such as sum, max, or a for loop that does not need random access.

When the full list is required, the comprehension is generally faster than an equivalent for loop with append. The comprehension's loop executes in C rather than as Python bytecode, and it avoids repeated method lookups for append. The difference grows with input size, but the exact ratio depends on the expression being evaluated, so measure when performance matters.

The filtering if and the ternary if/else have the same runtime cost per element: one predicate evaluation. The ternary adds no overhead beyond the branch itself, so choosing between them should be driven by semantics, not performance.

Common Mistakes and Edge Cases

The most frequent error is placing if/else in the wrong position. A ternary without else is a syntax error:

# SyntaxError: invalid syntax result = [n if n > 0 for n in numbers]

The ternary requires both branches. Conversely, placing else after the for clause is also invalid:

# SyntaxError: invalid syntax result = [n for n in numbers if n > 0 else 0]

The trailing if accepts no else because its job is filtering, not transformation.

Another edge case: an empty input sequence produces an empty result regardless of the conditional form. Both [n for n in [] if n > 0] and [n if n > 0 else 0 for n in []] return [].

Truthiness matters in the filtering form. A predicate that returns a falsy value for valid elements will silently drop them. For example, [n for n in values if n] drops 0 and None, which may be unintended when the sequence contains numeric values that can legitimately be zero.

When a Plain Loop Is More Readable

A comprehension with a long ternary chain or a complex predicate becomes harder to read than an explicit loop. The comprehension's compactness is an advantage only when the logic is simple enough to grasp at a glance.

Consider this comprehension:

result = [ process(item) if item.ready and item.owner == current_user else fallback(item) for item in data if item.status != "archived" and item.created > cutoff ]

The logic is correct, but a reader must parse two conditions in the filter and a compound condition in the ternary. An explicit loop separates the steps:

result = [] for item in data: if item.status == "archived" or item.created <= cutoff: continue if item.ready and item.owner == current_user: result.append(process(item)) else: result.append(fallback(item))

The loop version is longer but each decision is visible. When the comprehension's conditions grow beyond two or three terms, the loop version is usually the better maintainability choice. The comprehension remains the right tool for straightforward predicates and simple transformations.

python list comprehension if else: Practical Usage and Code | RYUSLOG DEV