The if...elif...else Statement
The last of the three, and the one for many possibilities and many outcomes. Each outcome gets a test of its own, the tests are checked from the top, and the first one that is True wins — the rest are not even looked at. elif is short for else if, and you may write as many as you need.
1Two outcomes are not always enough
A number is positive, negative, or zero. A student's grade is A, B, C, D or F. A day is Sunday, Saturday, Friday, or one of the others. These questions have no yes-or-no answer, so if…else — which offers exactly two roads — cannot express them.
What is needed is a row of tests, each with its own block, and a rule about which one runs.
2How it is written
if condition 1:
statement # runs when condition 1 is True
elif condition 2:
statement # runs when 1 was False and 2 is True
elif condition 3:
statement # runs when 1 and 2 were False and 3 is True
else:
statement # runs when every test above was False
next statementOne if at the top, as many elifs as you need in the middle, and at most one else at the bottom. Every elif carries its own condition — that is what makes it different from else, which carries none. All of them end in a colon, and all of them line up in the same column, because together they are one statement.
3Indentation: which block belongs to which test
With one if there was only one block, so it was obvious which lines belonged to it. Now there are several, and the only thing marking which is which is where the text starts.
The rule has not changed. A header — if, elif or else — ends in a colon. The lines indented under it, by 4 spaces, are its block, and they are the statements that run if that header is the one that wins. The next line back at the header's own column starts something new — either the next test, or the end of the whole statement.
if per >= 90:
grade = 'A' <- block of the if: runs only if per >= 90
print('Well done') <- same block: same indentation
elif per >= 70: <- back at the margin: a new test
grade = 'B' <- block of this elif: runs only if it wins
else:
grade = 'F' <- block of the else: runs if nothing above won
print('Grade =', grade) <- no indentation: outside all of them, always runs4A program with four outcomes
Sunday makes me happy. Saturday is for a movie. Friday means studying late. Every other day, I am bored. Four outcomes, so three tests and a default:
- the name of a day
- is it Sunday? else is it Saturday? else is it Friday?
- the message for that day, or the message for any other day
# print a message according to the day name
dayname = input('Enter the day name: ')
if dayname == 'Sunday':
print('I am happy')
elif dayname == 'Saturday':
print('I will watch a movie')
elif dayname == 'Friday':
print('I will study late night')
else:
print('I am bored')Enter the day name: Saturday I will watch a movie
Note the input is not cast with int() here — a day name is text, so the string input() hands back is exactly what is wanted, and == compares it with each name in turn.
# the same program, a day nobody wrote a test for
dayname = input('Enter the day name: ')
if dayname == 'Sunday':
print('I am happy')
elif dayname == 'Saturday':
print('I will watch a movie')
elif dayname == 'Friday':
print('I will study late night')
else:
print('I am bored')Enter the day name: Tuesday I am bored
Tuesday matches none of the three tests, so the else block runs. That is the default case: not a fourth day, but everything else there is.
'sunday' == 'Sunday' is False, so a student who types sunday is told I am bored. That is the program working exactly as written. Fixing it properly needs a string method you have already met — dayname.title() or dayname.lower() — applied before the tests.5The first True test wins
This is the rule that makes the shape work, and it has two halves. Python checks the tests from the top, and it stops at the first one that is True. Everything below that — the other tests and the else — is skipped without even being worked out.
Drag the percentage below and count the rungs Python never reaches:
Python starts at the top rung and stops at the first test that is True. Watch how many rungs it never even reaches.
2 of 4. Python stopped at the first True and skipped 2 rungs plus the else without looking at them.
Enter the percentage: 78
Grade = BNow press try the wrong order and slide back up to 95. A mark of 95 is reported as a D. Every test in that ladder is correct on its own — 95 really is more than 30 — but per >= 30 is checked first, it is True, and so nothing below it is ever looked at.
6The grade program, written properly
# work out the grade from the percentage
per = float(input('Enter the percentage: '))
if per >= 90:
grade = 'A'
elif per >= 70:
grade = 'B'
elif per >= 50:
grade = 'C'
elif per >= 30:
grade = 'D'
else:
grade = 'F'
print('Grade =', grade)Enter the percentage: 78 Grade = B
Look at what the ladder saved you. The second test is written per >= 70, not per >= 70 and per < 90. The upper half of the range is already taken care of: if the mark had been 90 or more, the first test would have won and this line would never have run. Each rung only has to rule out what is below it.
And print('Grade =', grade) is at the margin, outside every block, so it runs whichever grade was chosen. Indent it by four spaces and it would join the else block — printing only for students who failed.
7Three details worth knowing
The else is optional. if…elif with no else is legal, and then it is possible for no block at all to run — just like a plain if. Leave it out only when you really mean “in every other case, do nothing”.
Only ever one block runs. However many rungs a ladder has, exactly one block runs — or none, if there is no else and every test was False. Never two.
It is elif, not else if. Many languages write these as two words. Python has one keyword, elif; typing else if per >= 70: stops the program before it runs with SyntaxError: expected ':', because Python expected the else to end right there.
if. Two → if…else. Three or more → if…elif…else. The number of conditions you can imagine does not come into it; what matters is how many different things the program can end up doing.8Try it
Run the grade program with 95, 78 and 12. Then move the per >= 30 rung to the top and run it with 95 again — it will say D, and Python will not complain once.
9Recap
if…elif…else gives your program as many outcomes as you need. Each elif carries its own condition; the else at the bottom carries none and catches everything left over. The tests are checked top to bottom, the first True one wins, and the rest are never checked — which is why the order of the rungs is part of the program's meaning.per = 95 in a ladder that tests per >= 30 first, then 50, then 70, then 90. What is printed?
In an if…elif…elif…else, how many blocks can run in one go?
A line is indented by 4 spaces under 'elif per >= 70:'. When does it run?