Skip to content
VLSI Mentor

Python Part I · Module 9 · Conditional Statements

if, elif and else

Every program you have written so far runs every line, top to bottom, exactly once. That is enough to transform data but not enough to react to it. A regression that counts four errors and one fatal needs to say something different from one that counts none, and nothing you have met can express that difference. This chapter adds the one construct that can: a decision. You will see precisely what Python evaluates, how it chooses a block to run, why only one branch of a chain ever executes, and why writing the same two branches in the other order can silently make one of them unreachable.

Foundation16 min readPythonPart IFundamentalsConditionalsControl Flow

Part I · Module 9 · Chapter 9.1 · if, elif and else

1. The Smallest Real Decision

A regression run produces a count. What you want to say depends on the count.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
errors = 2

if errors > 0:
    print("review the log")

print("analysis complete")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
review the log
analysis complete

Now change one value — nothing else — and run it again:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
errors = 0

if errors > 0:
    print("review the log")

print("analysis complete")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
analysis complete

The first line disappeared. The second did not.

That is the whole shape of an if: an indented block that runs only under a condition, and the rest of the program, which runs regardless. The if governs its block. It does not govern everything below it.

2. What Python Actually Evaluates

It is tempting to read if errors > 0: as "if checks whether errors is greater than zero". That describes the effect and hides the mechanism, and the mechanism is what lets you reason about harder conditions later.

Two separate things happen.

First, Python evaluates the expression errors > 0. You already know what that produces on its own — Chapter 3.4 established it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
errors = 2
print(errors > 0)
print(type(errors > 0))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
True
<class 'bool'>

errors > 0 is an ordinary expression. It produces a value, and that value is a bool.

Second, control flow uses that value to choose a path. If the value is true, the indented block executes. If not, the block is skipped entirely.

So the model is:

  • evaluate the condition → get a truth value
  • select a path from that value
  • execute only the selected path
  • continue with the rest of the program
Four stages in sequence. One: evaluate the condition, written errors greater than zero. Two: a truth value, either True or False. Three: select a path — the indented block when the value is true, or skip it when the value is false. Four: continue with the rest of the program, which happens either way.One decision, four stages01EVALUATE THE CONDITIONerrors > 0 — an ordinary expression02A TRUTH VALUETrue or False, nothing else03SELECT A PATHrun the indented block, or skip it04CONTINUEthe unindented lines run either way
Figure 1 — what one if statement does, in order. The condition is evaluated first and on its own; only then does Python decide anything. Separating these two stages is what makes a compound condition in Chapter 9.3, and a match in Chapter 9.8, readable rather than mysterious.

Keeping stage 1 and stage 3 apart pays off immediately. A condition is just an expression, so anything that produces a value can be one — and everything you learned about expressions in Module 3 still applies inside an if.

3. else: The Other Path

Often there is something to say in both cases. else provides the path taken when the condition was not true.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
status = "PASS"

if status == "PASS":
    print("continue to the next stage")
else:
    print("investigate before continuing")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
continue to the next stage
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
status = "FAIL"

if status == "PASS":
    print("continue to the next stage")
else:
    print("investigate before continuing")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
investigate before continuing

Exactly one of those two blocks runs. Never both, never neither.

4. More Than Two Outcomes

Two paths are often not enough. A regression result is not pass-or-fail; it is clean, or it has errors, or it has a fatal, and those deserve three different verdicts.

elif adds an alternative with its own condition:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
fatals = 0
errors = 4

if fatals:
    status = "FATAL"
elif errors:
    status = "FAIL"
else:
    status = "PASS"

print(status)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
FAIL

Read it as one question with three possible answers. fatals is 0, so the first branch is not taken. errors is 4, so the second is. The else is not reached at all.

A chain may have as many elif branches as the problem needs, and the else is optional — leave it out and it is possible for no branch to run at all.

5. The First True Branch Wins

Here is the rule that makes a chain predictable:

Python evaluates the conditions from top to bottom. The first one that is true selects its block. That block runs, and the entire rest of the chain is skipped.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
coverage = 93

if coverage >= 95:
    print("excellent")
elif coverage >= 90:
    print("good")
else:
    print("needs work")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
good

93 >= 95 is false, so the first branch is passed over. 93 >= 90 is true, so the second branch runs — and else never gets a chance, even though the chain continues past it on the page.

6. The Rest of the Chain Is Not Even Evaluated

"Skipped" is stronger than it sounds. Python does not evaluate the later conditions and discard the results. It does not evaluate them at all.

That is testable. Put an expression in a later condition that would certainly fail if it were evaluated:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
errors = 3

if errors > 0:
    status = "FAIL"
elif 1 / 0:
    status = "impossible"

print(status)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
FAIL

1 / 0 is a ZeroDivisionError waiting to happen. It never happens. The first branch matched, so Python stopped — it never looked at the second condition, so the division never ran.

7. Branch Order Is Meaning

Because the first true branch wins, the order you write branches in is part of what they mean. Reorder a chain and you can change its answer — or make a branch that can never be selected.

Here is a chain that is broken by design. Read it, predict the output for a score of 97, and then look:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
score = 97

if score >= 80:
    print("good")
elif score >= 95:
    print("excellent")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
good

A 97 is excellent, and the program said good.

Nothing is wrong with either condition in isolation. The problem is the order. Every score that satisfies score >= 95 also satisfies score >= 80, so the first branch catches it first, and the second branch can never run for any input at all. It is dead code that looks alive.

Written the other way round, both branches become reachable:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
score = 97

if score >= 95:
    print("excellent")
elif score >= 80:
    print("good")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
excellent

For an ordered chain over one quantity, the working rule is: start at the most selective end. Thresholds that are hardest to satisfy go first.

8. Boundaries Are Where Conditions Go Wrong

Once the order is right, the remaining question is what happens exactly at each threshold. >= includes the boundary value and > does not, and the difference only ever shows up at one input.

Take the corrected chain and test the values on and around its two thresholds:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
if 79 >= 95:
    print("79: excellent")
elif 79 >= 80:
    print("79: good")
else:
    print("79: needs work")

if 80 >= 95:
    print("80: excellent")
elif 80 >= 80:
    print("80: good")
else:
    print("80: needs work")

if 95 >= 95:
    print("95: excellent")
elif 95 >= 80:
    print("95: good")
else:
    print("95: needs work")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
79: needs work
80: good
95: excellent
Input>= 95>= 80Selected branch
79FalseFalseelse
80FalseTrueelif
94FalseTrueelif
95True—if
97True—if

The dashes are not omissions. For 95 and 97 the first condition already matched, so >= 80 was never evaluated — Section 6's rule, visible in a table.

Note where the behaviour actually changes: between 79 and 80, and between 94 and 95. Testing 50 and 100 would have told you almost nothing. Test the boundary and its two neighbours, every time.

9. Several Independent ifs Are Not a Chain

This is the misconception worth the most. Two separate if statements and an if/elif chain look similar and behave differently.

Two independent if statements:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
value = 12

if value > 5:
    print("greater than five")

if value > 10:
    print("greater than ten")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
greater than five
greater than ten

Both ran. They are two unrelated questions, each answered on its own.

The same two conditions as a chain:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
value = 12

if value > 5:
    print("greater than five")
elif value > 10:
    print("greater than ten")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
greater than five

One ran. They are one question with two candidate answers, and the first match ended it.

In fact this particular chain is worse than it looks. Every value above 10 is also above 5, so elif value > 10: is unreachable for every input — it is Section 7's bug, arrived at by converting two good independent checks into a chain rather than by writing the thresholds in the wrong order. Changing the form changed the meaning, and one of the two questions stopped being asked at all.

Same data, same conditions, different output — because the two forms ask different things:

FormQuestion it asksHow many blocks can run
separate if statementswhich of these are true?any number, including all
if / elif chainwhich is the first true one?at most one

Choose by meaning, not by habit. A test can be both slow and failing, and you want to hear about both — that is two if statements. A test is clean, failing, or fatal and never two of those at once — that is a chain.

10. Predict, Run, Observe

Work out all four before reading the output.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# A
errors = 0
if errors > 0:
    print("A: errors")
print("A: done")

# B
temp = 85
if temp >= 100:
    print("B: critical")
elif temp >= 80:
    print("B: warm")
elif temp >= 90:
    print("B: hot")
else:
    print("B: normal")

# C
width = 8
if width > 4:
    print("C: wide")
if width > 6:
    print("C: wider")
if width > 16:
    print("C: widest")

# D
status = "WARN"
if status == "PASS":
    print("D: ship")
elif status == "WARN":
    print("D: review")
else:
    print("D: block")

The verified output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
A: done
B: warm
C: wide
C: wider
D: review

A — the condition is false, so the block is skipped; the unindented line runs anyway.

B — 85 >= 100 is false, 85 >= 80 is true, so B: warm is selected and the chain stops. Notice the third branch: temp >= 90 sits below temp >= 80, so it is unreachable for every input, exactly like Section 7. A temperature of 95 would also print B: warm.

C — three independent statements, two of which are true. Both print.

D — the second branch matches and the else is not reached.

11. Exercises

Exercise 1 — predict the branch. For utilization = 90, say which line prints and why, then verify:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
if utilization > 90:
    print("over")
elif utilization >= 90:
    print("at the limit")
else:
    print("under")

Exercise 2 — find the unreachable branch. One branch below can never be selected. Name it, explain in one sentence why, and rewrite the chain so every branch is reachable.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
if errors >= 1:
    print("some errors")
elif errors >= 100:
    print("severe")
else:
    print("clean")

Exercise 3 — chain or separate. For each pair of questions, say whether it should be two if statements or one if/elif chain, in one sentence each: (a) did the test fail, and did it run longer than an hour (b) is the result PASS, FAIL or FATAL (c) is the log missing, and is the log empty (d) is a seed below 1000, between 1000 and 9999, or above.

Exercise 4 — boundary table. For the chain in Exercise 1, build a table like Section 8's for the inputs 89, 90 and 91. Mark which conditions were evaluated and which were never reached.

Exercise 5 — repair the order. This chain is meant to report the most severe condition that applies. Fix it, then verify with fatals = 1, errors = 5 and with fatals = 0, errors = 5.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
if errors > 0:
    verdict = "FAIL"
elif fatals > 0:
    verdict = "FATAL"
else:
    verdict = "PASS"

Exercise 6 — prove the chain stops. Using the technique from Section 6, write a four-line program that would crash if Python evaluated the second condition of a chain, and show that it does not. Explain what your program proves.

Exercise 7 — design from requirements. A coverage report is signed off at 98 or above, acceptable from 90 to just under 98, at risk from 75 to just under 90, and blocking below 75. Write the chain. Then verify it at 74, 75, 89, 90, 97, 98 and 100 and say why those seven values are the right ones to test.

Exercise 8 — same data, two shapes. Given runtime = 4200 and errors = 0, write the checks for "took over an hour" and "reported no errors" first as two if statements and then as an if/elif chain. Run both, and explain in two sentences which one answers the question a reviewer actually asked.

12. Summary

  • An if runs its indented block only when a condition is true, and the unindented lines after it run either way.
  • A condition is an ordinary expression. Python evaluates it first, on its own, producing a value — then control flow uses that value to select a path.
  • else is the path taken when nothing above it matched. It has no condition of its own.
  • elif adds an alternative with its own condition. A chain is one question with several candidate answers.
  • The first true branch wins and the rest of the chain is skipped.
  • The rest of the chain is never evaluated — elif 1 / 0: after a matched branch does not raise, which proves it.
  • Branch order is part of the meaning. Wider conditions above narrower ones make the narrower ones unreachable, silently.
  • Start an ordered chain at the most selective end, and ask of every branch whether any input can reach it.
  • Conditions go wrong at boundaries. Test the threshold and its two neighbours, not convenient round numbers.
  • Separate if statements ask "which of these are true?"; a chain asks "which is the first true one?" Any number of the first can run; at most one of the second.

The next chapter looks at the only thing that marks where a branch begins and ends: the indentation.

Where this fits

Part of the Python curriculum.