Conditionals (if/elif/else)
Beginner⏱45-55 minutes📖15 min readLesson 5 of 10

Conditionals (if/elif/else)

Learn how Python chooses a branch with if, elif and else, how truthiness and conditional expressions work, and when match beats a chain of tests

At 9:04 on a Monday, a school's new grade script prints a D for a student who scored 85. The teacher checks the paper twice, then checks the printed total against the answer key. Both say 85, and the script still insists on a D. The bug is not in the arithmetic and not in the scanner. It lives in the order of five small tests, and one test near the top catches every passing score before the more precise tests can speak.

The script was written by someone who understood each test on its own. They did not yet know the rule that decides how the tests work together: Python tests from the top, runs the first branch that is true, and then leaves the whole chain.

This is lesson five of the course. By the end you will write two-way and multi-way decisions, nest them without hiding the common path, judge any value as true or false, compress a simple choice into one expression, and dispatch on the shape of data with match. Every claim here runs in a Python 3.15 REPL, and the interactive checks let you confirm each rule as it arrives.

Key terms

Condition
An expression that Python evaluates as true or false, such as score >= 80 or an empty list.
Branch
One indented suite of code that runs only when its condition is selected.
Suite
The indented block of statements that belongs to an if, elif, else or case line.
First-match semantics
The rule that a chain tests from the top and runs only the first branch whose condition is true.
Truthiness
The true or false value that Python gives any object when a condition needs a boolean answer.
Conditional expression
The one-line form a if condition else b, which produces one of two values instead of running a suite.
Structural pattern matching
The match and case statement added in Python 3.10 for dispatching on the shape or value of data.
Wildcard
The underscore pattern case _, which matches any subject and normally sits last.
Guard
An extra if condition attached to a case arm, such as case n if n > 0.

1. The Decision That Runs First

A condition is any expression that Python can judge as true or false. The if line evaluates that expression once, and when the answer is true, Python runs the indented suite below it. The colon is part of the syntax, and the indentation is what marks the boundary of the suite.

python
score = 85 if score >= 60: grade = "D" elif score >= 70: grade = "C" elif score >= 80: grade = "B" elif score >= 90: grade = "A" else: grade = "F" print(grade)

Run that block and the screen shows D. The first test asks whether 85 is at least 60, which is true, so Python runs grade = "D" and skips every later test. The later tests are not wrong on their own. They are simply unreachable for this score because an earlier branch already claimed it.

This behavior is called first-match semantics. A chain has no fall-through, unlike the switch statement in C, so an elif never runs after a true branch and no earlier condition is checked twice. The diagram follows the corrected order, where the narrow high bands are tested before the wide low band.

100%
Description

A flowchart for the section 1. The Decision That Runs First, showing the path and decision points described in the surrounding text.

The corrected chain starts at 90 and walks down, because each test is narrower than the one below it. The broken chain started at 60 and walked up, so its first test swallowed every passing score. When ranges overlap, put the most specific range first, or the general branch will hide it forever.

📌Important

A branch chain is not a list of independent rules. It is an ordered search that stops at the first true condition, and that single habit explains both correct code and the most common conditional bug.

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A school script receives a score of 85 and runs this chain: `if score >= 60:` sets D, then `elif score >= 70:` sets C, then `elif score >= 80:` sets B, then `elif score >= 90:` sets A, and `else:` sets F. Which grade is stored, and why?

2. if and if/else: the Two-Branch Gate

The simplest decision has one test and one fallback. An else line takes no condition, always sits at the same indentation as its if, and runs when every earlier test was false. The pair forms a two-branch gate that covers every possible value.

python
password = "swordfish" if password == "swordfish": print("Welcome back") else: print("Access denied")

The comparison uses two equals signs. A single = assigns a value, while == asks whether two values are equal, and mixing them up is the most common syntax error in beginner conditions. The walrus operator := is the one assignment form allowed inside an expression, and it exists for cases where you want to bind a value and test it in the same line.

python
items = ["tea", "cake", "jam"] if (count := len(items)) > 2: print(f"Large order with {count} items")

The parentheses around the walrus are required in this position, because the grammar needs to know where the assigned expression ends. Use it sparingly. A separate assignment line is usually clearer, and clarity beats a saved line.

PEP 8 asks for four spaces per indentation level and warns against mixing tabs with spaces, because indentation is syntax rather than decoration.

Sometimes the correct action for a branch is nothing at all. Python still requires a suite after the colon, so pass supplies an empty body that does nothing when it runs.

python
if password == "": pass # a deliberate placeholder while the check is designed else: print("Password present")
💡Tip

Write if user is None: when absence is the question, and write if not user: when any empty or false value should count. The two checks answer different questions, and choosing the narrow one prevents surprises later.

Practice Question
How to answer

Multiple-choice question with 2 options. Select one option, then choose Check Answer.

A learner writes `if balance = 100:` to test whether a bank balance equals 100. Does Python accept that line and run the branch when balance holds 100?

Matching Question
How to answer

Matching exercise with 5 pairs. Match each item on the left with its answer on the right.

Match each conditional construct to the job it performs.

if condition:
Drop here
elif condition:
Drop here
else:
Drop here
pass
Drop here
:=
Drop here

Drag answers from here:

runs its suite when the condition is truthy
is tested only after every earlier branch failed
runs when all earlier tests failed and takes no condition
supplies an empty suite where syntax requires a body
binds a name inside an expression such as a condition

3. if/elif/else and the Order of Checks

An elif adds another test to the same chain. Python reaches it only when every earlier condition was false, which means each elif can assume the earlier cases are gone. That assumption is what makes ordered ranges and staged checks readable.

python
age = 70 if age < 5: price = 0.00 elif age < 18: price = 8.50 elif age >= 65: price = 11.00 else: price = 16.00 print(f"Ticket price: {price:.2f}")

For age 70, the first two tests fail and the senior test succeeds, so the price is 11.00. For age 3, the first test succeeds and every later test is skipped. The order matters because the under 18 test would also be true for a small child if it came first, yet the child should pay nothing.

A sequence diagram makes the early exit visible. Each test is a message to the condition evaluator, and the first true reply sends control to one branch while the remaining tests stay silent.

100%
Description

A sequence diagram for the section 3. if/elif/else and the Order of Checks, showing the order of messages and replies described in the surrounding text.

Ordering also decides which branch is reachable. A common beginner mistake is to put else before a final elif, which is a syntax error, because else must be the last member of a chain. Another is to place a broad test first and then wonder why the narrow test below it never fires.

⚠️Warning

An unreachable branch is worse than a missing branch, because the code looks complete and passes a quick read. Put the most specific range first, and test the boundary values such as 17, 18, 64 and 65 before you ship.

Use the ordering exercise to build the habit. The grade bands must run from the highest score to the lowest, because each lower test is wider than the one above it.

Ordering Question
How to answer

Ordering exercise with 5 items. Move them into the correct order, then check your answer.

Order the grade checks so that a score of 85 receives a B under first-match semantics.

if score >= 90: grade = A
elif score >= 80: grade = B
elif score >= 70: grade = C
elif score >= 60: grade = D
else: grade = F
Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A ticket script sets age to 17 and runs this chain: `if age < 5:` price 0.00, `elif age < 18:` price 8.50, `elif age >= 65:` price 11.00, `else:` price 16.00. Which price is stored?

4. Nesting, and How to Flatten It

A nested conditional places one if inside the suite of another. Nesting mirrors a decision that happens in stages, such as checking a username before checking a password, so it can be the clearest shape for a short chain of related checks.

python
username = "admin" password = "secret123" has_id = True if username == "admin": if password == "secret123": if has_id: print("Entry allowed") else: print("ID required") else: print("Wrong password") else: print("Unknown user")

The code above answers three questions in order, and each inner block runs only when its parent branch was selected. That is correct, but the common success path sits at the deepest level, which makes a reader track three indentation levels before finding the happy ending.

A flatter chain says the same thing with less tracking. Each guard handles one failure and leaves early, so the success line sits at the end with no extra indentation.

python
if username != "admin": print("Unknown user") elif password != "secret123": print("Wrong password") elif not has_id: print("ID required") else: print("Entry allowed")

Short-circuit evaluation makes guarded conditions safe. In the expression if user and user.is_active:, Python evaluates user first, and when it is false the right side never runs, so an attribute lookup on None cannot happen.

The state diagram shows the same login logic as a set of transitions. Each arrow is one condition, and the first true transition decides the next state.

100%
Description

A state diagram for the section 4. Nesting, and How to Flatten It, showing the states and transitions described in the surrounding text.

ℹ️Note

📚 Did you know? A nested chain and a flat elif chain can produce the same output while differing in reachability. Flattening is not cosmetic: it puts the common path where a reader sees it first, and it removes branches that a deep indent can hide from a quick review.

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A login function nests four if blocks, and the successful path sits at the deepest level. Which refactor keeps the same decisions while making the common path easier to review?

5. Truthiness: What Counts as True

Every object has a truth value, and if value: asks for that value rather than for an explicit True. The built-in bool() exposes the same answer, so if value: and if bool(value): make the same decision.

The falsy set is short and exact. Everything outside it is truthy, including text that looks like a number and a list that contains only zero.

Value
Truth value
Everyday reading
None
falsy
an explicit absence
False
falsy
the false boolean
0, 0.0, 0j
falsy
numeric zero in each number family
""
falsy
empty text
[], (), {}, set(), range(0)
falsy
an empty collection
"0", [0], -1
truthy
non-empty text or a non-zero number
python
>>> bool("0") True >>> bool([0]) True >>> bool(0.0) False >>> bool(range(0)) False

The two surprising entries are "0" and [0]. Text is judged by whether it contains characters, and a list is judged by whether it contains items, so neither cares about the numeric meaning of what it holds. The bool type itself has exactly two constant instances, True and False, and bool() converts any value that can be interpreted as a truth value.

Truthiness removes clutter from everyday checks. An empty cart, a missing name and a count of zero each produce a natural condition without a comparison.

python
items = [] count = 5 name = "" if not items: print("Cart is empty") if count: print(f"Processing {count} items") if not name: print("Name missing")
ℹ️Note

📚 Did you know? The falsy list is closed and documented, so "0", [0] and a tuple holding only False are all truthy. Beginners often expect the contents to decide, yet Python asks only whether the container is empty.

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

Which value causes `if value:` to skip its body when value holds that object?

Fill in the Blanks
How to answer

Fill-in-the-blank exercise with 1 blanks. Type the missing words, then check your answer.

Complete the guard that prints a message only when the shopping cart is empty.

items = [] if blank items: print("Cart is empty")

Word Bank, drag words into the blanks above:

not
is
==
bool

6. The Conditional Expression

The conditional expression chooses one of two values in a single expression. Its shape is a if condition else b, and it produces a when the condition is true and b otherwise. Because it is an expression, it can sit inside an assignment, a function call or an f-string.

python
age = 20 status = "Adult" if age >= 18 else "Minor" print(status)

Both sides must produce a value, because the expression has to hand something back whichever way the test goes. That requirement is what separates it from an if statement, whose branches may print, return or do nothing at all.

python
score = 85 band = "pass" if score >= 60 else "fail" message = f"Result: {band}" print(message)

Nesting is legal, and it is usually a mistake. A nested conditional expression packs several tests into one line and forces the reader to parse the grouping from the inside out. When three or more outcomes exist, an if/elif/else chain states the order openly and keeps each case on its own line.

💡Tip

Use the conditional expression when both outcomes are short values, such as a label, a price or a default. Reach for if/elif/else when the branches run statements, when they need comments, or when a third case appears.

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A weather script runs `label = "hot" if temperature > 30 else "mild"` when temperature holds 30. Which label is stored?

7. match and case: Patterns from Python 3.10

Python 3.10 added match, a statement for choosing an arm based on the shape or value of data. Each case line holds a pattern, and the first pattern that matches runs its suite. Like an if/elif chain, match has no fall-through: once an arm runs, the statement ends.

python
def handle(status): match status: case 200 | 201: return "success" case 404: return "missing" case 500: return "server error" case _: return "unexpected" print(handle(404))

The case _: line is the wildcard, and it matches any subject that reached it. It must come last to be useful, because an earlier wildcard would swallow every later arm. The vertical bar in case 200 | 201: is an OR pattern, so either literal selects that arm.

Patterns can also describe structure. A sequence pattern such as case [x, y]: matches a two-item list and binds each item, while a mapping pattern such as case {"status": s}: matches a dictionary that contains a status key. A class pattern such as case Point(x=0, y=0): matches an instance whose attributes fit the given subpatterns.

A bare name in a pattern captures, and a dotted name compares. This difference is the single most important rule in the whole feature, and it is easy to miss because both forms look like ordinary names.

python
from enum import Enum class Color(Enum): RED = 1 GREEN = 2 def describe(value): match value: case Color.RED: return "stop" case Color.GREEN: return "go" case _: return "unknown" print(describe(Color.RED))

Color.RED is dotted, so the pattern compares the subject with that constant. If the first arm said case RED: instead, it would capture any value, bind it to RED, and make every later arm unreachable.

A guard adds a condition to a pattern with if. Guards are how match handles ranges, because a pattern such as case 1..10: is not Python syntax.

python
def sign(value): match value: case n if n < 0: return "negative" case 0: return "zero" case n if n > 0: return "positive" print(sign(-3))
📌Important

A bare name in a case always captures and therefore always matches. Put literal and dotted patterns first, keep case _: last, and use a guard when the decision depends on a range rather than a shape.

match is a statement, not an expression, and it does not replace every if. Choose it when the question is the shape or literal value of data, such as a command name, a response code, a parsed event or a small record. Choose if/elif when the question is a range, a boolean combination or a business rule, because those tests read naturally as conditions and need no pattern.

100%
Description

A quadrant chart for the section 7. match and case: Patterns from Python 3.10, placing the options along the two axes described in the surrounding text.

ℹ️Note

📚 Did you know? Captured names in a case leak into the surrounding scope like ordinary assignment, so a pattern can bind a name that the next line reads. The wildcard _ never binds, which is one reason it is a safe final arm.

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A function runs `match command:` with arms `case "start":`, `case "stop":` and `case _:`. The caller passes the text "pause". Which arm runs?

Practice Question
How to answer

Multiple-choice question with 2 options. Select one option, then choose Check Answer.

In a match statement, `case RED:` compares the subject with an existing variable named RED, and `case Color.RED:` also compares the subject with a constant. Are both patterns comparisons?

8. The Conditional Toolkit in 2026

2026 Updates (as of November 2026)

ℹ️Note

What changed recently, and what still works the same. Every line below was checked against a primary source in November 2026:

  • Python 3.15.2 is the current stable release (3.15.0 shipped on 2026-10-09, and 3.15.2 followed on 2026-10-25). A beginner can target the 3.15 series and use match without a compatibility guard.
  • match is unchanged in Python 3.15. The statement still follows PEP 634 from Python 3.10, with first-match arms, wildcards and guards.
  • Python 3.10 reached end of life on 2026-10-01. It introduced match, yet it no longer receives fixes, so new code should target 3.11 or newer.
  • The official tutorial still teaches if, elif, else, match and pass in one control flow chapter. That chapter remains the fastest primary reference when a pattern form is unclear.
ℹ️Note

📚 Did you know? match arrived in Python 3.10, and the very series that introduced it reached end of life in October 2026. The feature is now older than the support window of its first release, which is a useful reminder to check a version before copying an old tutorial.

Real-World Case Studies

Meta: routing requests across Instagram and Threads

Meta's engineering blog on 30 June 2026 calls Python its most used language and names Instagram and Threads among the backends built with it. A request router in such a service has to choose one handler from several candidates, and the handler that matches first owns the request for the rest of its life. First-match semantics turns that routing table into a readable chain, provided the specific routes are tested before the general fallback.

Netflix: decisions across the content lifecycle

The Netflix Tech Blog in April 2019 describes Python across the full content lifecycle, including the tooling around its Open Connect CDN. A content pipeline constantly decides whether an asset needs encoding, a refresh or no action, and each decision depends on the current state of that asset. An ordered chain of guards keeps those states exclusive, so one asset cannot be scheduled twice by two overlapping branches.

Dropbox: the desktop client and its migration

Dropbox described its Python desktop client in 2018 and 2019, along with one of the largest Python 2 to Python 3 migrations and later type checking close to 4 million lines. A sync client decides whether a local file is new, changed, deleted or in conflict, and each outcome needs its own branch. Clear ordering and explicit truthiness checks make those decisions reviewable at scale, which matters when a wrong branch can overwrite a user's work.

The HTTP status table as a dispatch example

The status handler from section 7 is a miniature of a real API gateway. A response code is a literal value, so a match statement with OR patterns and a final wildcard states the policy in one place. A range such as every code from 500 to 599 is a different question, so that case belongs in a guard or an if/elif chain instead of a literal list.

Practice Questions

Answer these before the next lesson. Each stem stands on its own, so review sessions can show them without any surrounding page. The inline questions earlier in the sections count too, and every id stays stable for scheduling.

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A developer writes a match statement with `case _:` as the first arm, followed by `case 404:` and `case 500:`. What happens when the subject is 404?

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A seating script runs `if seat % 2 == 0:` to set the label left, and its else branch sets the label right. When seat holds 7, which label is stored?

Practice Question
How to answer

Multiple-choice question with 2 options. Select one option, then choose Check Answer.

A budget script runs `if 0.1 + 0.2 == 0.3:` and expects the body to run. Does that condition evaluate to true in Python?

What Comes Next

The grade script from the opening now has a clear repair: order the tests from the narrowest high band to the widest low band, or move the checks into a match statement if each band is a literal value. Either way, the first true branch owns the score, and the remaining branches stay silent.

Conditionals decide what happens once. The next lesson adds repetition, so a program can apply the same decision to every item in a list instead of writing one branch per value. The video below is a full-course reference, and its control flow chapter restates this lesson from a second voice.

A long-form companion course: watch the control flow chapter when you want conditionals explained again in a different teaching styleWatch on YouTube
Description

A video walkthrough that supports the section What Comes Next and repeats its main ideas in a second voice.

✅Success

Key Takeaways:

  1. An if statement evaluates a condition once and runs its indented suite when the result is truthy, with a colon before the suite and consistent indentation inside it.
  2. An if/elif/else chain follows first-match semantics: tests run from the top, only the first true branch runs, and there is no fall-through.
  3. Order overlapping ranges from the most specific to the most general, or a broad early test will make every narrow test below it unreachable.
  4. else takes no condition and closes the chain, while elif adds another ordered test and is reached only after earlier tests fail.
  5. Nesting mirrors staged decisions, and flattening with elif guards or early returns keeps the common path shallow and reviewable.
  6. The falsy values are None, False, numeric zero, empty text and empty collections; everything else is truthy, including "0" and [0].
  7. a if condition else b is an expression that yields one of two values, and an if/elif/else chain is clearer once a third outcome appears.
  8. match and case arrived in Python 3.10 and run only the first matching arm, so specific patterns come first and case _: comes last.
  9. A bare name in a pattern captures any value, a dotted name compares with a constant, and a guard such as case n if n > 0: adds a range test.
  10. Prefer if/elif for ranges, boolean rules and business logic, and prefer match when the shape or literal value of data is the real question.

References

Every factual claim links to its source, with the access date printed so the source can be rechecked.

  1. [1]Compound statementsDocumentation

    Python Software Foundation · Accessed 2026-11-04

  2. [2]More Control Flow ToolsDocumentation

    Python Software Foundation · Accessed 2026-11-04

  3. Python Software Foundation · Accessed 2026-11-04

  4. [4]Truth value testingDocumentation

    Python Software Foundation · Accessed 2026-11-04

  5. [5]Built-in typesDocumentation

    Python Software Foundation · Accessed 2026-11-04

  6. Python Software Foundation · Accessed 2026-11-04

  7. Python Software Foundation · Accessed 2026-11-04

  8. Python Software Foundation · Accessed 2026-11-04

Progress50%