PYTHON / CONTROL FLOW
elif chains and mutually exclusive branches
Order and structure elif chains so that exactly one branch runs, using the fact that reaching an elif proves every condition above it was false.
What you will learn
- Read an elif chain top to bottom: the first true condition wins, the rest are skipped
- Order overlapping conditions narrowest first so broad tests don't swallow special cases
- Drop redundant bounds like `and score < 90`; the earlier branch already ruled that out
- Use separate ifs when several labels can apply, elif when exactly one should
Understanding elif chains and mutually exclusive branches
An elif chain is a single compound statement, not a pile of separate tests. Python evaluates the conditions from top to bottom, stops at the first one that is true, runs that block, and jumps past the whole rest of the chain without evaluating anything else. At most one block runs, and if no condition is true and there is no else, nothing runs at all.
The useful consequence is that arriving at an elif is itself information: every condition above it was false. So in a grade chain, `elif score >= 80` already means the score is below 90, and writing `elif score >= 80 and score < 90` adds a test that can never be false. The mental model is a sieve, where each branch only sees what the branches above rejected.
That same property is why order decides correctness when conditions overlap. If `score >= 70` comes first it catches 95 as well, and the branches for 80 and 90 become unreachable code that Python will happily never run. Sort overlapping conditions from the narrowest to the widest; when the cases genuinely cannot overlap, order is only a matter of readability. Reach for separate `if` statements instead when more than one case can legitimately be true at the same time.
def grade(score):
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
else:
return "F"
def broken_grade(score):
if score >= 70:
return "C"
elif score >= 80:
return "B"
elif score >= 90:
return "A"
else:
return "F"
for s in (95, 85, 75, 60):
print(s, grade(s), broken_grade(s))
An elif chain tests conditions in order and lets only the first true one execute, so every branch implicitly carries the negation of the ones above it.
Worked examples
Separate ifs collect, elif picks one
The same three conditions produce different results depending on whether they are independent ifs or one chain.
def classify_if(n):
labels = []
if n % 2 == 0:
labels.append("even")
if n % 3 == 0:
labels.append("multiple of 3")
if n % 5 == 0:
labels.append("multiple of 5")
return labels
def classify_elif(n):
labels = []
if n % 2 == 0:
labels.append("even")
elif n % 3 == 0:
labels.append("multiple of 3")
elif n % 5 == 0:
labels.append("multiple of 5")
return labels
for n in (30, 9, 25):
print(n, classify_if(n), classify_elif(n))
Example explained
Line 1For 30 all three conditions are true, so the independent ifs append three labels while the chain stops after the first match.
Line 2For 9 the first condition is false, so the chain moves on and both versions agree.
Line 3For 25 the chain evaluates two false conditions before the third matches, which shows the tests below are reached only after failures above.
Line 4The results diverge only when more than one condition can be true, which is exactly when elif is the wrong tool.
A chain with no else may run nothing
Without a final else, a variable assigned only inside the branches can stay undefined.
def sign_word(n):
if n > 0:
word = "positive"
elif n < 0:
word = "negative"
return word
print(sign_word(4))
try:
print(sign_word(0))
except UnboundLocalError:
print("word was never assigned: no branch matched")
Example explained
Line 1For 4 the first condition is true, `word` gets a value, and the elif is never evaluated.
Line 2For 0 both conditions are false, so neither assignment happens and the chain falls through silently.
Line 3`return word` then fails with UnboundLocalError, because the name is local to the function but was never bound.
Line 4Adding `else: word = "zero"` makes the chain exhaustive and removes the failure mode entirely.
Important notes
`elif` must come before `else`, and a chain has at most one `else`; putting an `elif` after the `else` is a SyntaxError, not a runtime problem.
A long chain comparing one variable against constant values is usually clearer as a dictionary lookup, since elif shines when the conditions are real expressions rather than equality checks.
Common mistakes
Writing the widest condition first, such as `if score >= 70` above `elif score >= 90`: every high score gets the lowest label and the branches below become unreachable, with no error to warn you.
Using separate `if` statements where each branch assigns the same variable: a later test re-examines the value, possibly one an earlier branch just changed, and overwrites the result instead of leaving the first decision alone.
Ending a chain with no else and then reading a variable set only inside the branches: unmatched input raises UnboundLocalError, or the function returns None if the branches used return.
Try it yourself
Change, predict, then run
Write `categorize(code)` that returns "info", "success", "redirect", "client error" or "server error" for an HTTP status code using one elif chain, and print it for 100, 200, 301, 404 and 500. Then swap two adjacent branches and print again to see which labels break.
Open the Python workspaceCheck your understanding
A function contains `if n % 2 == 0: ... elif n % 4 == 0: ...`. For n = 8, why can the elif branch never run?
- Both branches run, but the second one overwrites the result of the first.
- Python checks every condition and keeps the most specific match.
- Multiples of 4 are also even, so the first true test ends the chain; the narrower test has to come first.
- `8 % 4` evaluates to 0, which is falsy, so the elif condition fails.
Show answer
An elif is reached only when every earlier condition was false. Since `8 % 2 == 0` is true, the chain stops there and `n % 4 == 0` is never evaluated at all, so the narrower multiple-of-4 test must be placed above the even test. The first option describes what separate `if` statements would do; in a chain at most one body ever executes. The last option confuses the condition `n % 4 == 0`, which is True, with the raw value `8 % 4`, which is 0.