Python if, elif and else: Writing Conditions That Don't Overlap
An if/elif chain stops at the first true condition. Put the widest one first and the others never run, with no error. Order your conditions, test the edges, and make else mean what you think.
An if/elif/else chain stops at the first condition that is true. Everything else follows from that. Most bugs in these chains are not syntax errors. They're conditions in the wrong order, or two conditions that overlap, and Python quietly picks the first one.
Skip ahead: If you already know the syntax, go to "The order bug". That's the part that matters.
How the chain runs
temperature = 31
if temperature >= 30:
print("Hot")
elif temperature >= 20:
print("Warm")
else:
print("Cool")
Hot
Python checks from the top. 31 >= 30 is true, so it prints Hot and skips the rest of the chain. It never checks >= 20, even though that's also true. One chain, one branch at most.
That's the difference from writing separate if statements:
temperature = 31
if temperature >= 30:
print("Hot")
if temperature >= 20:
print("Warm")
Hot
Warm
Two separate ifs are two separate questions. Both can be true, and both run. Use separate ifs when you really mean "check each of these". Use elif when exactly one answer should win.
The order bug
Here's a grading function that looks fine:
def grade(score):
if score >= 60:
return "Pass"
elif score >= 90:
return "Excellent"
else:
return "Fail"
print(grade(95))
Pass
No error. Wrong answer. 95 >= 60 is true, so the first branch wins, and "Excellent" can never happen. That line of code is dead.
The fix is to check the narrowest condition first:
def grade(score):
if score >= 90:
return "Excellent"
elif score >= 60:
return "Pass"
else:
return "Fail"
for score in [95, 90, 89, 60, 59, 0]:
print(score, grade(score))
95 Excellent
90 Excellent
89 Pass
60 Pass
59 Fail
0 Fail
Notice the test scores: 90, 89, 60 and 59 are the edges. Bugs live at the edges. If the rule says "90 and above is Excellent", test 90 and 89, not just 95.
Make the ranges not overlap
With numbers, there's a simple habit: go in one direction (high to low or low to high) and use the same kind of comparison every time. Python also lets you write a range in one line:
def shipping_fee(weight_kg):
if weight_kg <= 0:
raise ValueError("weight must be more than 0")
elif weight_kg <= 1:
return 50
elif weight_kg <= 5:
return 120
elif weight_kg <= 20:
return 300
else:
return None
for weight in [0.5, 1, 1.01, 5, 20, 21]:
print(weight, shipping_fee(weight))
0.5 50
1 50
1.01 120
5 120
20 300
21 None
Each elif only runs when the ones above it were false, so weight_kg <= 5 already means "more than 1 and at most 5". You don't need to write 1 < weight_kg <= 5. You can, and it's fine if it makes the rule clearer to the reader, but then make sure the edges match the line above.
⚠ Warning: Mixing < and <= in one chain is how gaps happen. If one line says < 1 and the next says > 1, a weight of exactly 1 matches nothing and falls into else. Pick one style per chain.
What else should really mean
else catches everything that didn't match. That includes values you didn't think about. In the shipping example, I made zero and negative weights an error, and over 20 kg returns None so the caller knows there's no fee for it. A lazy else: return 300 would happily charge 300 for a weight of -5.
The rule I'd use: if else covers more than one real case, list the cases you expect and let else handle only the truly unexpected ones, loudly.
Combining conditions: and, or, not
age = 17
has_permit = True
if age >= 18 or has_permit and age >= 16:
print("Can drive")
else:
print("Cannot drive")
if age >= 18 or (has_permit and age >= 16):
print("Same answer, clearer")
Can drive
Same answer, clearer
and is checked before or, like multiplication before addition. Both lines give the same result, but the second one says it out loud. When you mix and and or, add the brackets. The next reader shouldn't need to remember the rule.
Common mistakes
- Wide condition first. Put the narrowest condition at the top.
- **
ifwhere you meantelif.** Two branches run, or a later one overwrites the first result. - **
if x == 1 or 2:** This is always true, because2on its own counts as true. Writeif x == 1 or x == 2:orif x in (1, 2):. - Testing only the middle values. Test each edge and one value past it.
What happens if you skip the edges
The chain works for every value you tried. Then a customer enters exactly 90, or exactly 1 kg, and gets the wrong grade or the wrong fee. The code never crashed, so nobody looked at it.
If your chain has four branches, how many test values do you need to check every edge, and did you write them?
About
How Python picks one branch, the order bug that makes branches unreachable, ranges without gaps, and and/or with brackets. After this, you can write a chain that gives the right answer at every edge.
- Responsible
- Jay P
- Last Update
- 09/17/2026
- Reading Time
- 5 min
Reviews
Sign in to write a reviewComments (0)
Sign in to commentNo comments yet.