score = 96
if score >= 60:
grade = "Pass"
elif score >= 90:
grade = "Excellent"The first condition already matches 96, so the more specific 90+ branch can never run.
Learn with diagrams, code, systems and practical examples.
Choose which code should run based on conditions.
Real programs behave differently depending on input, state, or business rules.
An if statement checks a condition. elif adds another condition if earlier ones did not match. else handles the remaining case.
Run this example first. Do not change several things at once; confirm the basic behavior, then experiment.
score = 84
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
else:
grade = "C or below"
print(grade) An if statement checks a condition. elif adds another condition if earlier ones did not match. else handles the remaining case.
BThe example is intentionally small. Focus on the chapter’s main idea before adding extra syntax or framework code.
Ordering broad conditions before specific ones so the specific branch can never run.
Order conditions from most specific or highest priority to more general cases.
These are deliberately small. If you can complete them without copying the example, you are ready to continue.
Core Python · next-day preparation
A program becomes useful when it can react to facts. Python’s if statement lets you ask a yes-or-no question and run a block only when that condition is true. elif lets you try another condition when the earlier one did not match, and else handles the remaining case.
Suppose an order needs manual review when its total is unusually high. Begin with one condition before introducing a full chain.
order_total = 160
if order_total > 150:
print("Manual review") Expected output:
Manual review The condition order_total > 150 is a Boolean expression. It evaluates to either True or False. If it is true, the indented block runs. If it is false, Python skips that block.
A shipping method is a good example because one order should receive one final category. Put the highest-priority rule first, then the next rule, then a fallback.
order_total = 48
if order_total >= 75:
shipping = "free"
elif order_total >= 30:
shipping = "standard"
else:
shipping = "pickup"
print(shipping) Expected output: standard.
Python checks order_total >= 75 first. It is false, so Python checks the elif. That condition is true, so Python assigns "standard" and stops checking the remaining branches in this chain.
score = 96
if score >= 60:
grade = "Pass"
elif score >= 90:
grade = "Excellent"The first condition already matches 96, so the more specific 90+ branch can never run.
score = 96
if score >= 90:
grade = "Excellent"
elif score >= 60:
grade = "Pass"
else:
grade = "Review"Put the narrower or higher-priority case before the broader case when the branches overlap.
An if / elif / else chain chooses at most one branch. Two separate if statements are different: both can run.
if temperature >= 30:
label = "hot"
elif temperature >= 20:
label = "mild"
else:
label = "cool"Use this when the outcomes compete and you want exactly one classification.
if is_member:
print("Member discount")
if has_coupon:
print("Coupon applied")Use separate checks when both facts can be true and both actions should happen.
if status == "paid" or "pending":The second operand is a non-empty string, which is truthy. Write if status == "paid" or status == "pending":, or use membership such as if status in ("paid", "pending"):.
elif for independent actionsIf both actions should be allowed to run, use two if statements. An elif is skipped after an earlier branch matches.
An else is optional. Add one when “everything else” is a meaningful case that deserves explicit behavior.
If invalid data should be rejected, validate it explicitly. Do not let an impossible or malformed value quietly fall into a normal business category.
Name a meaningful Boolean such as is_free_shipping when the rule is used repeatedly or needs explanation.
Prefer a readable if / elif / else chain when several mutually exclusive cases are on the same level.
Imagine a small delivery tool with three facts: whether the address is valid, whether same-day capacity exists, and whether the order total qualifies for free standard delivery.
address_valid = True
same_day_capacity = False
order_total = 82
if not address_valid:
result = "fix address"
elif same_day_capacity:
result = "same-day delivery"
elif order_total >= 75:
result = "free standard delivery"
else:
result = "standard delivery fee"
print(result) Expected output: free standard delivery.
Notice the order. Invalid addresses are handled first because the rest of the routing logic should not matter until the input is usable. Then same-day capacity has priority. Only after those cases do we consider the order-total rule.
order_total = 75 in the shipping example. Which branch runs, and why?same_day_capacity to True. Which later conditions are no longer evaluated?if starts a conditional decision.elif adds another condition only when earlier branches did not match.else handles the remaining case and has no condition.Next chapter: Loops — repeat work without duplicating code.
Trace lab · predict before reveal
Branching mistakes are often hard to spot because every individual condition looks reasonable. The reliable habit is to trace the chain in order: evaluate one condition, decide whether it is true, and stop as soon as a branch in the chain runs. Use these exercises to practise that habit before relying on intuition.
total = 95
if total >= 50:
label = "standard reward"
elif total >= 90:
label = "premium reward"
else:
label = "no reward"
print(label) The output is standard reward. The 50+ condition is true first, so Python runs that branch and never evaluates the 90+ elif. If premium orders should receive a different result, the 90+ rule belongs first.
is_member = True
has_coupon = True
if is_member:
print("member benefit")
elif has_coupon:
print("coupon benefit") Only member benefit prints. The elif belongs to the same exclusive chain, so it is skipped after the member branch matches. If the requirements say both benefits can apply, use two separate if statements.
quantity = -2
if quantity >= 10:
message = "bulk order"
elif quantity >= 1:
message = "regular order"
else:
message = "empty order"
print(message) The code prints empty order, but that may be a domain bug: -2 is not the same situation as zero. Add an explicit invalid-input branch such as if quantity < 0: before the normal order categories. Branch code should reflect meaningful domain states, not merely force every value into some label.
user = None
if user is not None and user.is_admin:
result = "admin"
else:
result = "standard"
print(result) The output is standard. Because user is not None is false, Python does not evaluate user.is_admin. This connects the previous Booleans chapter to branching: build a safe condition first, then decide what branch should run.
| Question | If yes | If no |
|---|---|---|
| Are these outcomes mutually exclusive? | An if / elif / else chain may fit. | Consider independent if statements. |
| Can two conditions both be true? | Order the higher-priority or narrower case first. | Order still matters for readability, but overlap is less risky. |
| Can input be invalid? | Handle invalid state explicitly before normal categories. | Keep the branch model focused on real outcomes. |
| Is the condition getting hard to read? | Name a Boolean or extract a helper function. | Keep the small condition close to the decision. |
Build a small triage function using four facts: whether required contact information exists, whether the issue is a security incident, whether the customer is blocked from working, and whether the request is informational. First write the priority order in plain English. Then turn that order into one readable branch chain.
A useful order might be: reject incomplete requests first; route security incidents to the security queue; route work-blocking issues to urgent support; otherwise route the request to normal support. Do not copy that order blindly—explain why each branch has its position.
has_contact = True
is_security_incident = False
is_blocking = True
if not has_contact:
queue = "needs information"
elif is_security_incident:
queue = "security"
elif is_blocking:
queue = "urgent support"
else:
queue = "normal support"
print(queue) Expected output: urgent support. Now change two facts so more than one condition could be true. Predict which branch wins before running the code, then decide whether that priority matches the business rule.
if / elif chain as two independent if statements and explain how the possible outputs change.else.Quick reference
Choose the shape of the decision before writing the conditions. This keeps mutually exclusive outcomes separate from independent actions and makes branch order easier to explain.
| Intent | Pattern | Reason | Common mistake |
|---|---|---|---|
| One optional action | if | No competing outcome is needed. | Adding an empty or artificial else. |
| Exactly two outcomes | if / else | Every valid input belongs to one side. | Using two independent checks and allowing both actions. |
| One result from several categories | if / elif / else | Only the first matching branch runs. | Putting a broad condition before a narrower one. |
| Several actions may all happen | separate if statements | Each fact is checked independently. | Using elif and skipping later actions. |
| Reject unusable input first | validation if | Bad input should not fall into a normal category. | Letting a catch-all else hide an invalid state. |
if is_member:
apply_member_discount()
if has_coupon:
apply_coupon()Both facts can be true, so both actions may run.
if input_needs_fixing:
route = "fix input"
elif is_urgent:
route = "urgent"
else:
route = "normal"Only one final route is wanted, so the order is part of the program behavior.
Branch coverage planner
For a ladder such as order_total >= 75, one example above the threshold is not enough. Use this small matrix to choose test inputs that expose ordering, boundary, validation and fallback mistakes before they reach production.
| Case to test | Example input | What should happen | Bug this can reveal |
|---|---|---|---|
| Just below a threshold | order_total = 74 | Do not enter the >= 75 branch. | Using >, >=, or the wrong threshold unintentionally. |
| Exactly on a threshold | order_total = 75 | Enter the >= 75 branch. | Off-by-one boundary logic. |
| Two conditions are both true | same_day_capacity = True, order_total = 100 | The earlier same-day branch wins if the ladder is intentionally prioritized. | A broad or high-priority branch being placed in the wrong order. |
| Invalid domain input | order_total = -1 | Validation should reject it before normal delivery categories. | A catch-all else disguising bad input as a valid state. |
| No explicit condition matches | Valid input below every special rule | The final else should represent the intended ordinary case. | An incomplete ladder or an else that is doing too many unrelated jobs. |
Try it: run the overlapping and threshold cases in the Which branch wins? explorer below, predict the branch first, then compare the result with this matrix.
Next action: choose the branching shape here, then trace one concrete input through the conditions before running the program.
Interactive practice
Change the facts, then watch Python's first-match rule choose exactly one route. This is the same reasoning you should do before you run a real if / elif / else chain.
Current result
free standard deliveryThe address is valid, same-day capacity is false, and the order total qualifies for the 75+ branch.
if not address_valid → fix addresselif same_day_capacity → same-day deliveryelif order_total >= 75 → free standard deliveryelse → standard delivery feeif not address_valid:
result = "fix address"
elif same_day_capacity:
result = "same-day delivery"
elif order_total >= 75:
result = "free standard delivery"
else:
result = "standard delivery fee"