Python List Comprehension Multiple Conditions
python list comprehension multiple conditions: Use multiple conditions in Python list comprehensions: filter with chained if clauses, transform with if-else expression...
python list comprehension multiple conditions requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
Python list comprehensions combine iteration, filtering, and transformation into a single expression. When you need to apply multiple conditions in a python list comprehension, the syntax has two distinct forms that behave very differently: multiple if clauses that filter items, and an if-else expression that transforms each value. Mixing them up produces code that either filters when you meant to transform, or raises a SyntaxError when the conditional expression lands in the wrong position.
The Two Kinds of Conditions in a Comprehension
A list comprehension has this general shape:
[expression for item in iterable if condition]
The if condition part is a filter. It keeps items for which the condition is true and discards the rest. You can chain several if clauses:
numbers = range(1, 101) result = [n for n in numbers if n % 2 == 0 if n % 3 == 0]
This keeps numbers divisible by both 2 and 3, which means 6, 12, 18, and so on. Multiple if clauses combine with logical AND. You can write the same filter as a single predicate:
result = [n for n in numbers if n % 2 == 0 and n % 3 == 0]
Both forms produce identical results. The chained version reads like a sequence of filters; the and version reads like one combined predicate. The choice is mostly about readability, not behavior.
Using if-else to Transform Values
The other form uses a conditional expression in the output position:
values = [-5, 3, -2, 7, 0] result = [x if x > 0 else 0 for x in values]
Here x if x > 0 else 0 is evaluated for every item. Positive values pass through unchanged; everything else becomes 0. This is a transformation, not a filter. The resulting list keeps its original length.
The conditional expression is a full Python expression, so it can be combined with other operations or nested:
result = ["even" if x % 2 == 0 else "odd" for x in range(10)]
Why Position Determines Behavior
The filter if appears after the for clause. The conditional expression appears in the output position, before the for. Placing a conditional expression after for is a syntax error:
# SyntaxError: invalid syntax result = [x for x in values if x > 0 else 0]
The parser expects if to introduce a filter there, not a ternary. If you need both a filter and a transformation, you combine the two forms:
values = [-5, 3, -2, 7, 0] result = [x * 10 if x > 0 else x for x in values if x != 0]
Reading order matters: the trailing if x != 0 filters first, then the leading x * 10 if x > 0 else x transforms whatever remains. The filter runs before the output expression, so the transformation only ever sees items that survived.
Multiple for Clauses with Conditions
Nested loops in a comprehension follow the same order as nested for statements:
matrix = [[1, 2], [3, 4]] flat = [n for row in matrix for n in row if n % 2 == 0]
The for row in matrix loop runs first, then for n in row, then the filter. You can attach conditions at either level:
pairs = [(a, b) for a in range(3) for b in range(3) if a != b if a + b > 2]
The conditions apply to the innermost scope, so both a and b are available in each filter. The evaluation order is the same as a nested loop: the first loop variable changes slowest, and each filter runs as soon as its dependent variables are bound.
Readability Limits
A comprehension with two for clauses and two conditions is already hard to scan. Add a conditional expression and the line becomes dense:
result = [x if x > 0 else -x for row in matrix for x in row if x != 0 if abs(x) < 10]
This is correct Python, but a reader has to parse the output expression, two loops, and two filters in a single line. When the logic grows past that point, a regular loop is usually clearer:
result = [] for row in matrix: for x in row: if x != 0 and abs(x) < 10: result.append(x if x > 0 else -x)
The loop version makes the evaluation order explicit and leaves room for comments. It also supports break, continue, and statements that a comprehension cannot contain. A comprehension is not always the better tool; it is the more compact tool.
Performance and Memory Considerations
A list comprehension builds the entire list in memory before any consumer sees it. For large inputs, that allocation can dominate runtime. A generator expression keeps the same filtering and transformation logic but yields items lazily:
gen = (x * 10 if x > 0 else x for x in values if x != 0)
The syntax differs only in the brackets. The generator avoids building the full list, which matters when the result is consumed by a loop, sum(), any(), or another function that processes items one at a time. If you need the actual list, for indexing, repeated iteration, or passing to a function that requires a sequence, the list comprehension is the right choice.
The filter also short-circuits per item: an item that fails the first condition is never evaluated against later conditions, and the output expression never runs for it. That ordering is worth keeping in mind when some conditions are more expensive to evaluate than others. Placing a cheap condition before an expensive one can reduce the number of expensive evaluations, whether you use a comprehension or a generator expression.