Kiru Lab  /  Foundations: Python as an Instrument  /  Python From First Principles

Making Decisions

if, elif, else — how a program takes one path rather than another, and the indentation rule that enforces it.

Code Walkthrough  ·  about 30 minutes

A branch lets a program do different things depending on a condition. Python writes this with `if`, optionally followed by any number of `elif` clauses and one `else`. The first condition that is True wins; the rest are skipped entirely.

A branch
loss = 0.42

if loss < 0.1:
    print("converged")
elif loss < 1.0:
    print("still training")
else:
    print("something is wrong")

# still training

Indentation is the syntax

Most languages mark blocks with braces. Python uses indentation — the lines belonging to an `if` are the lines indented under it. This means your code cannot look correct while being structured wrongly, which is a real advantage, and it means an inconsistent indent is a genuine error rather than a style complaint.

Indentation changes the meaning
for value in [1, 2, 3]:
    total = total + value
    print(total)          # runs every iteration: 1, 3, 6

for value in [1, 2, 3]:
    total = total + value
print(total)              # runs once, after the loop: 6

Use four spaces per level. Configure your editor to insert spaces when you press Tab, and never mix the two — a file with both is a file that looks fine and fails.

Conditions

Comparison and combination
a == b        # equal            (two equals signs — one is assignment)
a != b        # not equal
a < b, a >= b # ordering

x > 0 and y > 0       # both must hold
x > 0 or y > 0        # at least one
not converged         # negation

0 < score <= 100      # Python allows chaining; most languages do not

if items:             # idiomatic: "if the list is not empty"
    ...
if value is None:     # use `is` for None, never ==
    ...
The single-equals bug

Writing `if x = 5` instead of `if x == 5` is a syntax error in Python, which is a mercy — in several other languages it silently assigns and then evaluates as true. When you read code in another language later, this is one of the first things to check.


Hold on to

  • The first true branch wins; the rest are skipped
  • Indentation is structure, not decoration — four spaces, never tabs
  • Use `is` for None and `==` for values

Work through

Try each one before opening the solution. Getting it wrong first is most of where the learning happens.

  1. Write a function `describe_loss(loss)` returning "converged", "training", or "diverging" for values below 0.1, below 1.0, and above. Test all three branches.
    Hint

    Order the branches from the tightest condition to the loosest.

    Solution

    The order matters: check `< 0.1` before `< 1.0`, because 0.05 satisfies both and the first true branch wins. Reversing them would make the "converged" branch unreachable — a bug that produces no error at all.

    def describe_loss(loss):
        if loss < 0.1:
            return "converged"
        elif loss < 1.0:
            return "training"
        else:
            return "diverging"
    Check your work

    Paste this after your own code. If it runs without raising, you have it.

    assert describe_loss(0.05) == "converged"
    assert describe_loss(0.42) == "training"
    assert describe_loss(3.0) == "diverging"
    print("ok")
  2. Write a function that classifies a number as "negative", "zero", or "positive" without using `elif` — only `if` and `return`. Explain why early returns remove the need for elif.
    Hint

    A `return` ends the function immediately, so no later line can run.

    Solution

    Because `return` exits, each subsequent `if` is only reached when the previous ones were false — which is exactly what `elif` means. Early returns keep the code flat instead of nesting it, and they read as a list of cases rather than a tree.

    def classify(n):
        if n < 0:
            return "negative"
        if n == 0:
            return "zero"
        return "positive"
    Check your work

    Paste this after your own code. If it runs without raising, you have it.

    assert classify(-5) == "negative"
    assert classify(0) == "zero"
    assert classify(7) == "positive"
    print("ok")
  3. Take the two indentation examples from the lesson, run both with `total = 0` defined first, and explain in one sentence why the outputs differ.
    Hint

    Look at which lines are indented under the `for`.

    Solution

    In the first version `print` is inside the loop body, so it runs once per iteration and shows the running total: 1, 3, 6. In the second it is outside, so it runs once after the loop finishes and shows only 6. Nothing but indentation differs, which is the whole lesson.


Sign in to track your progress through the lab.