Skip to main content

Choosing a path: if, elif and else

A program can test a condition and run one block of lines or another. Learn if, elif and else, read them as flow charts, band the five quiz scores with cut-offs 70 and 50, and see which values Python counts as true.
P01.3.1L0 Foundation25 minIn review

Before this lesson

P01.1 How computers run programs P01.2 Values, variables and types

After this lesson you can

  • Explain what a block is, and how indentation shows where a block starts and ends.
  • Predict which block of an if, elif and else statement runs for a given value, using the rule that the first true test wins.
  • Draw the flow chart of an if, of an if with else, and of an if with elif and else.
  • Order the tests of a chain so that every block can be reached, and band the five study scores with the cut-offs 70 and 50.
  • Name the values that count as false in a condition (False, None, 0, 0.0 and the empty string) and check them with bool.

In review. The maths and code on this page are checked by automated tests on every change, but an independent reader has not signed it off yet. Spot a mistake or a confusing step? Tell us.

The question

A quiz has a pass mark of 50, and a score of 70 or more earns a distinction. Five students scored 55, 65, 80, 40 and 60. Every program so far has run each of its lines once, from top to bottom. How can a program give each student the right band, running some lines and skipping others, and why does the order in which it asks its questions matter?

Intuition

A program is a list of instructions carried out one after another (P01.1.1). To make a decision it needs a condition: an expression whose value is True or False, such as score >= 50 (P01.2.4). An if statement runs a group of lines only when its condition is true, and skips them when it is false. Which lines run, and in what order, is called the control flow of the program.

A flow chart draws control flow as a picture. This course draws every flow chart the same way: rounded boxes for start and end, rectangles for actions, and a diamond for each condition, with its two exits labelled True and False. Control enters at the top and follows the arrows.

A flow chart. From a rounded Start box an arrow leads to the action score = 55, then to a diamond score >= 70. Its True exit points right to the action band = 'distinction', drawn in grey and marked skipped. Its False exit points down to a second diamond, score >= 50, whose True exit points right to band = 'pass', filled yellow, and whose False exit points down to band = 'fail', grey and marked skipped. All three actions lead to print(score, band) and then to a rounded End box. The path taken for a score of 55 is drawn in thick green: Start, score = 55, the first diamond, its False exit, the second diamond, its True exit, band = 'pass', print, End. Notes beside the diamonds read 55 >= 70 is False and 55 >= 50 is True, and the output 55 pass is written beside End.
P01.3.1-F1

The banding as a flow chart, with the path taken by a score of 55 in green. The first test is False, so control drops to the second, which is True; band = 'pass' runs and every other block is skipped.

Read the picture from the top. The two diamonds are asked in order, and the first one that answers True decides where control goes. Once one block has run, control jumps past all the others to the line after the statement. So exactly one of the three bands is chosen, never two.

Build it up

Step 1. A header and a block. Here is the smallest if statement.

score = 55
if score >= 50:
    print('pass')
print('done')

The line if score >= 50: is a header: the keyword if, a condition and a colon. The lines under it that are indented, here by four spaces, form a block. The block ends at the first line that is indented less, so print('done') is not part of it and runs whatever the score. For 55 the program prints pass and then done; for 40 it prints only done.

Step 2. else: one of two blocks. An else: header at the same indentation as the if adds a second block, which runs exactly when the condition is false. Then one of the two blocks always runs, and never both.

Two panels, each with code above its flow chart. Left, titled if: run a block, or skip it. Code: if score >= 50:, then the indented print('pass') marked as the block, then print('done'). Its flow chart: a diamond score >= 50 whose True exit goes down through print('pass') to print('done'), and whose False exit goes round the right-hand side straight to print('done'), labelled skips the block. Right, titled if, else: one of two blocks runs. Code: if score >= 50: band = 'pass', else: band = 'fail', print(band), with the two indented lines marked block 1 and block 2. Its flow chart: a diamond with True leading down on the left to band = 'pass' and False leading down on the right to band = 'fail', both joining at print(band).
P01.3.1-F2

Two simpler shapes. Left: an if alone runs its block or skips it. Right: an if with an else always runs exactly one of its two blocks.

Step 3. elif: a chain of tests. For three bands we need two tests. elif is short for “else if”: it is a test that is made only when every test above it was False. A chain may have any number of elif parts, and at most one else, which comes last.

if score >= 70:
    band = 'distinction'
elif score >= 50:
    band = 'pass'
else:
    band = 'fail'

The formal statement

NoteThe if statement

An if statement is one if clause, then any number of elif clauses, then at most one else clause. Each clause is a header, which ends with a colon, and a block, the lines after it indented by the same amount.

Python evaluates the conditions one by one, from the top, until one is true. It runs that block and skips the rest of the statement: later conditions are not even evaluated. If every condition is false, it runs the else block if there is one, and otherwise nothing.

So with an else, exactly one block runs; without one, at most one. The Python reference says the same: the conditions are evaluated one by one until one is found to be true, that block (a “suite”, in its words) runs, and no other part of the statement is run or even evaluated.

What each block really tests. Because a test is made only after the ones above it failed, each block of the banding runs on a range of scores. Write \(s\) for the score.

  • The first block runs when \({s \ge 70}\).
  • The second block runs when \({s \ge 70}\) is False and \({s \ge 50}\) is True: that is, when \({s < 70}\) and \({s \ge 50}\), which P01.2.4 writes as 50 <= score < 70.
  • The else block runs when both tests are False: \({s < 70}\) and \({s < 50}\). Every number below 50 is also below 70, so this is simply \({s < 50}\).

So the band of a score \(s\) is decided like this:

\[ \begin{aligned} s \ge 70 &: \quad \text{distinction} \\ 50 \le s < 70 &: \quad \text{pass} \\ s < 50 &: \quad \text{fail} \end{aligned} \]

The three ranges do not overlap and leave no gap, so every score gets exactly one band. Notice that the second test only says score >= 50; the < 70 half comes free from the order.

Truth values. A condition does not have to be a bool. When it is not, Python decides whether it counts as true. The values that count as false are False, None, the number zero (0 and 0.0) and the empty string ''. Every other value met so far counts as true: any other number, even a negative one, and any string with at least one character in it, even '0' or ' '. (Empty lists, met in P01.6, count as false too.) The built-in bool applies the same rule and returns True or False.

Worked example

Band the five scores with the cut-offs 70 and 50. For each student, make the first test; make the second only if the first was False; fall through to else only if both were False.

  • Ama, 55: \({55 \ge 70}\) is False, so test again: \({55 \ge 50}\) is True. Band: pass.
  • Ben, 65: \({65 \ge 70}\) is False; \({65 \ge 50}\) is True. Band: pass.
  • Chen, 80: \({80 \ge 70}\) is True. Band: distinction. The second test is never made.
  • Dina, 40: \({40 \ge 70}\) is False; \({40 \ge 50}\) is False. The else block runs. Band: fail.
  • Eli, 60: \({60 \ge 70}\) is False; \({60 \ge 50}\) is True. Band: pass.
A table with one row per student and the columns student, score, score >= 70, score >= 50 and band. Ama 55: False, True, 'pass'. Ben 65: False, True, 'pass'. Chen 80: True, not tested, 'distinction'. Dina 40: False, False, 'fail'. Eli 60: False, True, 'pass'. In each row the cell that decided the band is filled yellow: the True of the second test for Ama, Ben and Eli, the True of the first test for Chen, and the band 'fail' for Dina, where no test was True and else decided. Below: Tally, 1 distinction, 3 passes, 1 fail.
P01.3.1-F3

The worked example as a trace. Yellow marks what decided each band: the first True test, or the else when no test was True.

The tally is one distinction (Chen), three passes (Ama, Ben, Eli) and one fail (Dina). Two cases deserve a second look. For Chen the second test is never made, because the first True test wins. For Dina no test is True, and that is exactly the case else exists for.

A rule that cuts one number at a fixed value is the simplest classifier there is: it sorts examples into classes. Lesson ML01.1.3 calls it a threshold rule, and there learning means choosing the cut-off from data instead of by hand.

Code

The banding for Ama’s score, exactly as above.

score = 55
if score >= 70:
    band = 'distinction'
elif score >= 50:
    band = 'pass'
else:
    band = 'fail'
print(score, band)
55 pass

To band Ben, change the first line to score = 65 and run the cell again; the trace above gives every result. Changing one line by hand five times is exactly the chore that the for loop of lesson P01.3.3 removes. A program of your own could also ask for the score as it runs, with score = int(input('Score? ')). The cells on this page cannot type, so they set the score directly.

Now Python’s own truth test. bool gives the verdict an if would reach.

print(bool(0), bool(0.0), bool(''), bool(None))
print(bool(55), bool(-1), bool('0'), bool(' '))

name = ''
if name:
    print('hello', name)
else:
    print('no name given')
False False False False
True True True True
no name given

The empty string counts as false, so the else block runs. Note the third value on the second line: '0' is a string with one character in it, so it is true, even though the number 0 is false.

Explore

This module’s interactive, the flow-chart tracer, lives in lesson P01.3.3. Its first program is this lesson’s banding: set the score with the slider, step through it, and watch which diamond answers True first. Try the scores 70, 50 and 49, which sit on the edges of the bands.

Pitfalls

Two number lines from 0 to 100 with the five scores 40, 55, 60, 65 and 80 marked as blue dots. Top, marked with a cross and titled score >= 50 tested first: above the line, bars show 'fail' from 0 to 50 and 'pass' from 50 to 100, a note reads 'distinction' is never reached, and below the line a note reads Chen's 80 gets 'pass'. Bottom, marked with a tick and titled score >= 70 tested first: bars show 'fail' from 0 to 50, 'pass' from 50 to 70 and 'distinction' from 70 to 100, and a note reads Chen's 80 gets 'distinction'.
P01.3.1-F4

Wrong beside right. With score >= 50 tested first, every score of 50 or more stops at the first test, so the distinction band can never be reached.

“The order of the tests does not matter.”

It does. Swap the two tests, so that if score >= 50: comes first and elif score >= 70: second. The second block would need score >= 50 to be False and score >= 70 to be True: a score below 50 and at least 70, which no number is. Chen’s 80 now stops at the first test and gets 'pass', and the five scores give four passes and one fail. Put the strictest test first.

“Three separate ifs do the same job as elif.”

They do not, because every if makes its own test. With if score >= 70: and then a separate if score >= 50:, a score of 80 passes both: band is set to 'distinction' and then, one line later, overwritten with 'pass'. elif makes the tests one chain, in which only the first True one counts.

“Indentation is only for looks.”

In Python the indentation is the block. Leave it out and the program does not even start:

score = 55
if score >= 50:
print('pass')
  File "band.py", line 3
    print('pass')
    ^^^^^
IndentationError: expected an indented block after 'if' statement on line 2

This message was copied from a run with Python 3.15; the wording and the ^ markers vary a little between versions. Writing = where == is meant, as in if score = 70:, is stopped the same way, with a SyntaxError that asks whether you meant ==.

“The text ‘0’ is false, like the number 0.”

Only the number is. '0' is a string with one character, so bool('0') is True. This matters because data read from a file arrives as text (P01.2.1): convert it with int before you test it.

Check yourself

Recall

1. What is a block, and how does Python know where it ends?

Show answer

The indented lines that follow a header ending in a colon. The block ends at the first line that is indented less than its lines.

2. In an if, elif and else statement, how many blocks run, and which?

Show answer

Exactly one: the block of the first condition that is true, or the else block when none is.

3. With the tests score >= 70 and then score >= 50, what band does a score of 70 get? And 69?

Show answer

70 gets distinction, because \({70 \ge 70}\) is True. 69 gets pass: the first test is False and \({69 \ge 50}\) is True.

4. Which of these count as false in a condition: 0, '0', '', None, -1, 0.0?

Show answer

0, '', None and 0.0. The string '0' has one character and -1 is not zero, so both count as true.

5. Why does testing score >= 50 before score >= 70 make the distinction band unreachable?

Show answer

Every score of at least 70 is also at least 50, so it stops at the first test, which wins. The elif score >= 70 test is never made for such a score.

Exercises

1. ★ Using the banding of this lesson, give the bands of the scores 70, 50, 49 and 100.

Show solution

70: \({70 \ge 70}\) is True, so distinction. 50: \({50 \ge 70}\) is False and \({50 \ge 50}\) is True, so pass. 49: both tests are False, so the else gives fail. 100: distinction. The cut-offs belong to the higher band, because the tests use >=.

2. ★★ A student writes the banding with three separate ifs and no elif:

if score >= 70:
    band = 'distinction'
if score >= 50:
    band = 'pass'
if score < 50:
    band = 'fail'

For which of the five scores 55, 65, 80, 40, 60 is the band wrong, and how do you fix it?

Show solution

Every test is now made for every score. For 55, 65 and 60 only the second test is True, so the band is 'pass', which is right. For 40 only the third is True: 'fail', right. For 80 the first test sets 'distinction', then the second test, \({80 \ge 50}\), is also True and overwrites it with 'pass'. Only Chen’s band is wrong. Writing elif for the second test and else instead of the third makes the tests one chain, in which the first True test wins.

3. ★★★ The study hours of the five students are 2, 4, 5, 1 and 3, and their results are pass, pass, pass, fail, pass. A rule predicts pass when hours >= c and fail otherwise. Find every whole number c for which the rule agrees with all five results, and write the rule as an if statement.

Show solution

The rule must say pass for 2, 4, 5 and 3 hours, so \({2 \ge c}\), which needs \({c \le 2}\). It must say fail for Dina’s 1 hour, so \({1 \ge c}\) must be False, which needs \({c > 1}\). The only whole number with \({1 < c \le 2}\) is \({c = 2}\). The rule is

if hours >= 2:
    prediction = 'pass'
else:
    prediction = 'fail'

Choosing c from the examples, instead of guessing it, is what it means for a threshold rule to learn (ML01.1).

Summary card

A condition chooses which block runs, and the first true test wins.

The anchor figure again: the flow chart of if, elif and else that bands a score, with two diamonds score >= 70 and score >= 50 and the blocks band = 'distinction', band = 'pass' and band = 'fail', and the path of a score of 55 in green through the two tests to band = 'pass'.
P01.3.1-F1

The banding as a flow chart.

  • Block. The indented lines after a header that ends in a colon.
  • if, elif, else. Tests are made from the top; the first True one runs its block, and the rest is skipped. else runs when no test is True.
  • Order. Put the strictest test first, or a later block can never be reached.
  • Truth. False, None, 0, 0.0 and '' count as false; every other value met so far is true. bool gives the verdict.

Sources and next steps

Sources. Each was opened and checked against this lesson on 12 November 2026.

  • Python Software Foundation, The Python Tutorial, section 4.1, if Statements. Zero or more elif parts and an optional else; elif is short for “else if”.
  • Python Software Foundation, The Python Language Reference, chapter 8, Compound statements. The opening of chapter 8 defines a clause as a header ending in a colon and a suite, the block; section 8.1 says the if statement selects exactly one suite by evaluating the expressions one by one until one is true, and runs the else suite when all are false. Section 6.11, Boolean operations, lists the values interpreted as false: False, None, numeric zero and empty strings and containers.
  • Allen B. Downey, Think Python, 3rd edition, chapter 5 (CC BY-NC-SA 4.0). Section 5.4 calls the indented statements after a header a block; 5.5 calls the alternatives branches; 5.6 says each condition is checked in order and only the first true branch runs.
  • Ana Bell, MIT OpenCourseWare 6.100L, Fall 2022, Lecture 3 slides (CC BY-NC-SA 4.0). Slides 2 and 3 recap branching: the first condition that is True is the one whose block runs, and indentation matters.

Next. P01.3.2 Repeating with while keeps the test but sends control back to it after the block, so that a block can run again and again.

This lesson unlocks

P01.3.2 Repeating with while

Your progress is saved in this browser only. No account, no tracking.
Back to top