Python course menu
Python Nested if Statements (and How to Flatten Them)
Learn nested conditions in Python: if statements inside other ifs, when nesting is useful, how to flatten deep nesting with and, elif, and early returns (guard clauses), with a leap year example.
On this page
A nested condition is an if statement inside another if (or else). It lets you make a second decision only after a first one has been made. Nesting is useful, but deep nesting quickly becomes hard to read, so this lesson also shows how to flatten it.
Example: entry to a show#
age = 25
has_ticket = True
if age >= 18:
if has_ticket:
print("Enjoy the show")
else:
print("Please buy a ticket")
else:
print("Adults only")Enjoy the showThe inner if/else is only reached when age >= 18. Each level of nesting adds another 4 spaces of indentation.
Flattening with elif#
The same logic can often be written without nesting by checking the "failure" cases first:
age = 25
has_ticket = False
if age < 18:
print("Adults only")
elif not has_ticket:
print("Please buy a ticket")
else:
print("Enjoy the show")Please buy a ticketEvery outcome is now at the same level, and the conditions read like a checklist.
Flattening with and#
When the inner if has no else, combine the conditions:
# Nested
if age >= 18:
if has_ticket:
print("Enjoy the show")
# Flat: same behaviour
if age >= 18 and has_ticket:
print("Enjoy the show")A classic: leap years#
A year is a leap year if it is divisible by 4, except years divisible by 100, unless they are also divisible by 400. Nested, it looks like this:
year = 2024
if year % 4 == 0:
if year % 100 == 0:
if year % 400 == 0:
leap = True
else:
leap = False
else:
leap = True
else:
leap = False
print(year, leap)2024 TrueIt works, but three levels of nesting are hard to follow. The same rule as one boolean expression:
for year in [2024, 1900, 2000, 2026]:
leap = year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
print(year, leap)2024 True
1900 False
2000 True
2026 FalseGuard clauses inside functions#
Inside a function, the cleanest way to avoid nesting is to return early when something is wrong. These early checks are called guard clauses:
def can_withdraw(balance, amount, card_blocked):
if card_blocked:
return "Card blocked"
if amount <= 0:
return "Invalid amount"
if amount > balance:
return "Insufficient funds"
return "Approved"
print(can_withdraw(1000, 300, False))
print(can_withdraw(1000, 3000, False))
print(can_withdraw(1000, 300, True))Approved
Insufficient funds
Card blockedEach problem is handled and dismissed at the top, and the "happy path" sits at the end, unindented.
When nesting is fine#
Nesting is natural when the inner decision only makes sense after the outer one, and both branches of the outer decision have their own sub-decisions. One level of nesting is perfectly normal.
Common mistakes#
Practice#
Practice exercise
Write code that finds the largest of three numbers a, b and c using nested if statements (without max()), and test it on (3, 9, 5), (7, 2, 7) and (1, 1, 1). Compare with max(a, b, c).
Show hint
First compare a with b. Inside each branch, compare the winner with c.
Show solution
for a, b, c in [(3, 9, 5), (7, 2, 7), (1, 1, 1)]:
if a >= b:
if a >= c:
largest = a
else:
largest = c
else:
if b >= c:
largest = b
else:
largest = c
print(largest, max(a, b, c))9 9
7 7
1 1In real code you would simply use max(a, b, c), but this exercise shows how nested decisions narrow down the answer.
Key takeaway#
Finished this lesson?