LambdaLabTM
Computer Science · Class 11 · Selection Statements
SelectionMany outcomes⏱️ 12 min read

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

shape.py
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 statement

One 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.

blocks.py
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 runs
Key Takeaway
The indentation is what joins a block to its test. Four spaces under a header means “these statements are that header's block”; back at the margin means “this line is not part of it”. Move a line in or out and you have not changed what it does — you have changed when it does it.

4A 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:

Input
what we ask the user for
  • the name of a day
Process
what we work out
  • is it Sunday? else is it Saturday? else is it Friday?
Output
what we show
  • the message for that day, or the message for any other day
dayname.py
# 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')
Output
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.

dayname.py
# 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')
Output
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.

Watch Out
Comparing text is fussy about capitals. '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:

🪜 Climbing the ladder

Python starts at the top rung and stops at the first test that is True. Watch how many rungs it never even reaches.

78.0
grade.py
headerbody — the indented blockoutside
if per >= 90:False
grade = 'A'
elif per >= 70:True
grade = 'B'
elif per >= 50:never checked
grade = 'C'
elif per >= 30:never checked
grade = 'D'
else:
grade = 'F'
rungs checked

2 of 4. Python stopped at the first True and skipped 2 rungs plus the else without looking at them.

output
Enter the percentage: 78
Grade = B

Now 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.

Watch Out
Order the tests from the narrowest to the widest. In a ladder of ranges, the test that catches the fewest values goes at the top. Put a wide test first and it swallows everything, and Python will not warn you: the program runs perfectly and gives the wrong answer, which is a logical error.

6The grade program, written properly

grade.py
# 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)
Output
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.

Which shape do I write?
Count the outcomes. One thing that might happen → 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.

grade.py

9Recap

Key Takeaway
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.
Quick Check

per = 95 in a ladder that tests per >= 30 first, then 50, then 70, then 90. What is printed?

Quick Check

In an if…elif…elif…else, how many blocks can run in one go?

Quick Check

A line is indented by 4 spaces under 'elif per >= 70:'. When does it run?