Making decisions: if / elif / else
Up to now, every program you have seen runs straight down the page — line 1, then line 2, then line 3 — and every line runs, every single time. That is fine for a calculator that always does the same thing. But real software has to choose. A banking app shows your balance only if you typed the right password. A game prints "You win" only if your score beat the target. A website greets a logged-in user by name but shows a "Sign in" button to a stranger. The tool that lets a program take one path or a different path is called a conditional, and that is the entire subject of this lesson.
What "branching" actually means
Imagine you are walking down a road and you reach a fork. A sign asks a simple yes-or-no question — "Is it raining?" — and you take the left path if the answer is yes and the right path if it is no. That fork is exactly what programmers call a branch. The program reaches a point, asks a question that can only be answered True or False, and then runs one chunk of code or a different chunk depending on the answer.
The yes-or-no question is called the condition. A condition is just an expression that evaluates to one of the two special values True or False (these are called booleans, after the mathematician George Boole). You met these in the previous lesson when you wrote comparisons like age >= 18 or price < 100. Each of those, when Python works it out, becomes either True or False — and that boolean is the answer the branch needs.
:::note Key idea in one sentence
A conditional is a block of code that runs only when its condition turns out to be True, and is skipped entirely when the condition is False.
:::
The if statement
The simplest branch is the if statement. In plain English it says: "if this condition is True, run the following lines; otherwise, skip them and carry on." Those "following lines" are called a block — one or more lines that belong together and are treated as a single unit.
Here is the smallest possible example. Read it slowly; we will name every piece directly underneath.
temp = 35
if temp > 30:
print("It's hot out") # this line runs, because 35 > 30 is True
print("Done") # this always runs: it is NOT indented under the if
# Output:
# It's hot out
# Done
Three parts make up that if:
- The keyword
if, followed by the conditiontemp > 30. Python works this out first; here it becomesTrue. - A colon
:at the very end of that line. The colon is Python's way of saying "a block is about to begin." Forgetting it is one of the most common beginner errors. - The indented block underneath — the
print(...)line, pushed in from the left margin. That indentation is how Python knows the line belongs to theif.
Indentation: what it is and why Python cares
Indentation means the blank space at the start of a line — the spaces you put before the first real character. In most programming languages, indentation is purely cosmetic: it makes code readable but the computer ignores it, and instead the language uses curly braces { } to mark where a block starts and stops. Python made a deliberate, unusual choice: it has no braces for this. The indentation itself is the block. Lines indented to the same depth under an if belong to that if; the first line that returns to the outer margin is outside it again.
The universal convention is 4 spaces per level, used consistently. Look again at the example: print("It's hot out") is indented 4 spaces, so it is inside the if. print("Done") is back at the margin (0 spaces), so it runs no matter what the condition was.
:::tip This is not a style nit — it is a hard rule
If you forget to indent the body, or you indent it unevenly (say 3 spaces on one line and 5 on the next), Python stops and refuses to run the program, reporting an IndentationError. The two things that catch every beginner are: (1) leaving off the colon : at the end of the if line, and (2) getting the indentation wrong. Pick 4 spaces and never mix spaces with tabs.
:::
# WRONG - the body is not indented, so Python raises IndentationError
if temp > 30:
print("It's hot out")
# RIGHT - 4 spaces in front of the body line
if temp > 30:
print("It's hot out")
else: the fallback path
An if on its own does something only when the condition is True; when it is False, nothing happens. Often you want a "plan B" — something to do in the False case instead. That is what else is for. else has no condition of its own; it simply runs when the if condition was False. Note that else also ends with a colon and has its own indented block.
temp = 12
if temp > 30:
print("It's hot out")
else:
print("Not hot today") # this runs: 12 > 30 is False
# Output:
# Not hot today
Exactly one of the two blocks runs — never both, never neither. The condition decides which.
elif: checking several conditions in order
Sometimes a yes/no split is not enough — you have several cases. elif (short for "else if") lets you test another condition when the previous one was False, before finally falling through to else. You can stack as many elif branches as you like. Python reads them top to bottom, stops at the first one that is True, runs only that block, and skips the rest of the ladder. This "first match wins, then stop" rule is the single most important thing to remember about elif.
Here is the classic worked example: turning a numeric test score into a letter grade.
score = 82
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "F"
print(grade) # B
Trace it with score = 82:
- Check
82 >= 90→False. Skip the A block. - Check
82 >= 80→True. Setgrade = "B", then jump out of the whole ladder. - The
>= 70check and theelseare never even looked at.
Now trace the same code with score = 65:
65 >= 90→False. Skip.65 >= 80→False. Skip.65 >= 70→False. Skip.- None matched, so the
elseruns:grade = "F". Output would beF.
Notice why the order matters and why elif is so convenient: by the time we reach elif score >= 80, we already know the score was below 90 (otherwise the first branch would have caught it). So we do not have to write elif score >= 80 and score < 90 — the ladder handles the upper bound for us automatically.
Truthiness: when a value counts as True or False
A condition does not have to be a literal comparison. You can put almost any value after if, and Python will decide whether to treat it as True or False. This is called truthiness. A small, fixed list of values are considered falsy (treated as False); everything else is truthy (treated as True).
The falsy values are the "empty" or "nothing" ones:
- The number zero:
0and0.0 - The empty string:
""(a string with no characters) - The empty list:
[] - The empty dictionary:
{} - The special "no value" object
None
Any other value — a non-zero number, a string with text in it, a list with items in it — is truthy. This lets you write very readable checks. For instance, if name: reads as "if name has something in it," because an empty string is falsy and a non-empty one is truthy.
name = ""
if name:
print("Hello, " + name)
else:
print("No name given") # this runs: "" is falsy
# Output: No name given
items = [1, 2]
if items:
print("The cart has stuff in it") # runs: a non-empty list is truthy
# Output: The cart has stuff in it
Combining conditions, and nesting
From the previous lesson you can join conditions with and (both must be True) and or (at least one must be True). You can also place an if inside another if — this is called nesting, and the inner block is simply indented one level deeper (8 spaces instead of 4). Compare the two styles below; they do the same thing.
# Nested - works, but harder to read
age = 20
member = True
if age >= 18:
if member:
print("Full access")
# Combined with 'and' - flatter and clearer
if age >= 18 and member:
print("Full access") # both True, so this runs
else:
print("Limited access")
When two conditions both have to hold, prefer joining them with and over nesting one if inside another — flatter code is easier to read and less likely to hide a bug. Save nesting for when the inner decision only makes sense after the outer one has passed.
Three bugs that bite every beginner
=instead of==. A single=assigns a value; a double==compares.if x = 5:is not a question and Python rejects it with a SyntaxError. You almost always wantif x == 5:("is x equal to 5?").- Wrong or missing indentation. Forgetting to indent the body, or mixing 3 and 4 spaces, gives an
IndentationError. Keep every line in a block at the same depth — 4 spaces. - Ordering an
elifladder wrong. Because the first True branch wins, putting the loosest test first swallows everything below it. - Forgetting the colon. Every
if,elif, andelseline ends in:. Leaving it off is a SyntaxError.
# BUG: loosest check first - everyone gets an "A"!
if score >= 70:
grade = "C"
elif score >= 90: # a 95 already matched >= 70 above, so this is never reached
grade = "A"
# Fix: order the ladder from strictest (highest) to loosest (lowest).
Why it matters
if runs a block when its condition is True, elif offers more conditions to try in order (first True wins, then stop), and else is the catch-all for when nothing matched. Python finds the block by the colon : at the end of the line and the consistent 4-space indentation underneath it. Any value can serve as a condition thanks to truthiness, where empty things (0, "", [], {}, None) count as False.
Conditionals let a program decide once. The natural next question is: what if you want to do something over and over — check every score in a class, or every word in a sentence? That is repetition, and it is exactly what the next lesson on loops is about. Loops and conditionals are the two building blocks behind nearly every program you will ever write.
Where this leads: branching logic is exactly what you trace when a bug report says the wrong path ran. See Where this leads next.
Practice
Your turn — write the if/elif/else grade ladder and run it live in your browser.
Write grade_for(score) that returns a letter grade: 90 or above returns 'A', 80 to 89 returns 'B', 70 to 79 returns 'C', and anything below 70 returns 'F'. Check the highest cutoff first.
Checkpoint
Making decisions: if / elif / else
Pass to unlock the Next button belowNext: Loops →