Control Flow: If / Elif / Else
Reviewed & published by Brayan K
Learn how to make your programs smart by having them make decisions based on conditions.
Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
- How if, elif, and else make programs make decisions
- How comparison operators (==, >, <) work in conditions
- How to combine conditions with and, or, not
- Nested if statements for complex logic
- The one-line ternary if expression
- Real-world examples like grade checkers and age validators
What is Control Flow?
Control flow is how your program decides what code to run based on conditions. Without it, programs would just run line by line, doing the same thing every time.
With control flow, your program can:
- Check if a user is old enough to vote
- Show different messages based on a score
- Validate passwords
- Make games react to player choices
Think of control flow like a traffic light. The light checks conditions (time, sensors) and decides whether to show green, yellow, or red. Your program works the same way!
🧠 How Python Reads Conditions: The Mental Model
Before writing a single line of control flow, build this mental model — it explains every behaviour you'll encounter.
Rule 1: Python reads conditions top to bottom
It checks the first if, then each elif in order. The moment one is True, it runs that block and skips all the rest.
Rule 2: Only ONE branch ever runs
Even if multiple conditions would be True, only the first True branch executes. This is why order matters when writing elif chains.
Rule 3: else is the safety net
else has no condition — it runs when none of the above conditions were True. It's optional but gives your program a guaranteed fallback.
Watch how order changes the result:
❌ Wrong order — catches everything at 90+:
score = 95
if score >= 60:
grade = "C" # ← This runs first!
elif score >= 80:
grade = "B" # Never reached
elif score >= 90:
grade = "A" # Never reached
print(grade) # "C" — WRONG✅ Correct order — highest first:
score = 95
if score >= 90:
grade = "A" # ← This runs!
elif score >= 80:
grade = "B"
elif score >= 60:
grade = "C"
print(grade) # "A" — CORRECTWhen using >= ranges, always check the most specific / highest condition first.
1. The if Statement
The if statement is the simplest form of control flow. It checks a condition and runs code only if that condition is True.
code to run if True
| Part | Description |
|---|---|
| if | Keyword that starts the condition check |
| condition | An expression that evaluates to True or False |
| : | Required colon at the end of the line |
| Indented code | Code that runs only if condition is True (4 spaces) |
# Simple if statement
age = 18
if age >= 18:
print("You can vote!")
print("You're an adult!")
print("This always prints")
# Try changing age to 15 and see what happens!
# ✅ Expected output:
# You can vote!
# You're an adult!
# This always prints2. The if-else Statement
What if you want to do something different when the condition is False? Use else to specify an alternative action.
If condition is True:
Run the first block, skip the else block
If condition is False:
Skip the first block, run the else block
# if-else example
temperature = 25
if temperature > 30:
print("It's hot outside!")
print("Stay hydrated!")
else:
print("The weather is nice.")
print("Enjoy your day!")
# Try: Change temperature to 35
# ✅ Expected output:
# The weather is nice.
# Enjoy your day!3. The if-elif-else Chain
When you have more than two possibilities, use elif (short for "else if") to check multiple conditions.
code if none are True
# Grading system example
score = 85
if score >= 90:
grade = "A"
print("Excellent work!")
elif score >= 80:
grade = "B"
print("Good job!")
elif score >= 70:
grade = "C"
print("Not bad!")
elif score >= 60:
grade = "D"
print("You passed.")
else:
grade = "F"
print("Need improvement.")
print(f"Your grade: {grade}")
# Try different scores: 95, 75, 55
# ✅ Expected output:
# Good job!
# Your grade: B🧑🏫 Worked example: a cinema ticket price
Here is the same idea doing real work. Every line is commented with what it produces and why, so you can trace the program the way Python does — top to bottom, stopping at the first condition that is True. Notice the last if is a separate statement, not an elif: that is deliberate, and the comments explain what it changes.
# WORKED EXAMPLE: a cinema ticket price calculator.
# Read it top to bottom - that is exactly the order Python reads it in.
age = 15 # the customer's age
is_student = False # do they have a student card?
day = "Tuesday" # this cinema runs a Tuesday discount
# Python tests the chain below in order and runs ONLY the first True branch.
if age < 5:
price = 0.00
category = "Infant" # under-5s go free
elif age < 16:
price = 7.50
category = "Child" # 15 < 16 is True, so this branch wins
elif age >= 65:
price = 8.00
category = "Senior"
elif is_student: # never reached here - an earlier branch already matched
price = 9.00
category = "Student"
else:
price = 12.00
category = "Adult" # the fallback when nothing above matched
# A separate if - NOT an elif - so this discount stacks on top of the category.
if day == "Tuesday":
price = price - 2.00 # 7.50 - 2.00 = 5.50
print(f"Category: {category}")
print(f"You pay: £{price:.2f}") # :.2f forces exactly two decimal places
# ✅ Output:
# Category: Child
# You pay: £5.50
# Experiment: set age = 70 and the Senior branch wins instead.
# Then set age = 20 and is_student = True - now the Student branch runs, because
# none of the age branches above it matched. Order really does decide the answer.
# ✅ Expected output:
# Category: Child
# You pay: £5.504. Comparison Operators in Conditions
Conditions use comparison operators to compare values. These always return True or False.
| Operator | Meaning | Example | Result |
|---|---|---|---|
| == | Equal to | 5 == 5 | True |
| != | Not equal to | 5 != 3 | True |
| > | Greater than | 10 > 5 | True |
| < | Less than | 3 < 7 | True |
| >= | Greater than or equal | 5 >= 5 | True |
| <= | Less than or equal | 4 <= 4 | True |
5. Combining Conditions with Logical Operators
You can combine multiple conditions using logical operators: and, or, and not.
| Operator | Description | Example |
|---|---|---|
| and | Both conditions must be True | age >= 18 and has_id |
| or | At least one condition must be True | age < 12 or age > 65 |
| not | Reverses the condition | not is_banned |
# Combining conditions
age = 25
has_ticket = True
is_vip = False
# Using 'and' - both must be True
if age >= 18 and has_ticket:
print("Welcome to the concert!")
# Using 'or' - at least one must be True
if age < 12 or age > 65:
print("You get a discount!")
else:
print("Regular price applies.")
# Using 'not' - reverses the condition
if not is_vip:
print("Please use the regular entrance.")
# Try changing the values!
# ✅ Expected output:
# Welcome to the concert!
# Regular price applies.
# Please use the regular entrance.🎯 Your turn: the library borrowing checker
Time to write some of it yourself. The program below is finished apart from three blanks: one keyword, one comparison operator and one logical operator — the three things this lesson has taught you. Replace each ___ and run it. The expected output is in a comment at the bottom, so you can check yourself without leaving the page.
# 🎯 YOUR TURN - finish the library borrowing checker
# Replace each ___ below, then press Run.
age = 14 # the borrower's age
has_card = True # do they have a library card?
fines_owed = 0.00 # unpaid fines, in pounds
book = "adult" # which section the book came from: "child" or "adult"
if not has_card:
print("You need a library card first.")
___ fines_owed > 0: # 👉 replace ___ with the keyword that means "otherwise, if"
print(f"Pay your £{fines_owed:.2f} fine before borrowing.")
else:
# An adult-section book needs the borrower to be 16 or over.
if book == "child" or age ___ 16: # 👉 replace ___ with the operator meaning "is at least"
print("Enjoy your book!")
else:
print("Sorry, that book is for ages 16 and over.")
# A tip shown only when BOTH of these are true.
if age < 16 ___ fines_owed == 0: # 👉 replace ___ with the logical operator meaning "both"
print("Tip: the children's section is upstairs.")
# ✅ Expected output once the blanks are filled in:
# Sorry, that book is for ages 16 and over.
# Tip: the children's section is upstairs.
# Then experiment: set age = 17 and run again. You should get one line only:
# "Enjoy your book!" - the under-16 tip no longer applies.⚡ Truthy and Falsy Values: Conditions Without ==
You don't always need to write == True or != "". Python evaluates any value as either truthy or falsy in a condition — and knowing this makes your code cleaner and more Pythonic.
Falsy values — treated as False
- 0 — the integer zero
- 0.0 — the float zero
- "" — empty string
- [] — empty list
- None — no value
- False — boolean False
Truthy values — treated as True
- 1, -5, 3.14 — any non-zero number
- "hello" — any non-empty string
- [1, 2] — any non-empty list
- True — boolean True
# Checking if a variable has a value
name = ""
if name: # Same as: if name != ""
print(f"Hello, {name}!")
else:
print("No name provided") # ← This runs
# Checking if a number is non-zero
score = 0
if not score: # Same as: if score == 0
print("You haven't scored yet!")
# Checking if a list has items (you'll learn lists soon)
items = []
if items:
print("Cart has items")
else:
print("Your cart is empty") # ← This runs
# 'None' check — very common in real code
result = None
if result is None:
print("No result yet — still processing")6. Nested If Statements
You can put an if statement inside another if statement. This is called nesting and is useful for complex decisions.
# Nested if example
age = 25
has_id = True
if age >= 18:
print("You're old enough.")
if has_id:
print("ID verified. Entry allowed!")
else:
print("Please show your ID.")
else:
print("Sorry, you must be 18 or older.")
# The inner if only runs if the outer if is True
# ✅ Expected output:
# You're old enough.
# ID verified. Entry allowed!🛡️ Guard Clauses: Writing Cleaner Conditions
Deeply nested if statements are hard to read. Professional Python developers use a technique called guard clauses — checking for bad conditions early and exiting, which keeps the main logic flat and readable.
❌ The "pyramid of doom" — deeply nested:
def process_order(user, cart, payment):
if user:
if user["verified"]:
if cart:
if len(cart) > 0:
if payment:
print("Order placed!")
else:
print("No payment")
else:
print("Cart empty")
else:
print("No cart")
else:
print("Not verified")
else:
print("No user")5 levels deep — hard to follow, easy to make mistakes
✅ Guard clauses — flat and readable:
def process_order(user, cart, payment):
if not user:
print("No user")
return
if not user["verified"]:
print("Not verified")
return
if not cart or len(cart) == 0:
print("Cart empty")
return
if not payment:
print("No payment")
return
print("Order placed!") # Clean!Each failure exits early — main logic is at ground level
The rule: reject bad cases first
Check for invalid input, missing data, or error conditions at the top. Once you've handled those, write the main happy-path logic without nesting. This is standard practice in professional codebases — it's called the early return pattern.
You'll use return properly when you learn functions in a later lesson. For now, just understand that flat code beats nested code.
7. Indentation: Python's Secret Sauce
Indentation is not optional in Python! It tells Python which code belongs to which block. Use 4 spaces (or 1 tab) for each level.
if age >= 18:
print("Adult")
print("Can vote")if age >= 18:
print("Adult") # Error!- IndentationError: expected an indented block - Missing indentation after colon
- IndentationError: unexpected indent - Random indentation where not needed
- IndentationError: unindent does not match - Mixing tabs and spaces
Common Mistakes to Avoid
if x = 5: is wrong. Use if x == 5:
if x == 5 is wrong. Add colon: if x == 5:
Wrong capitalization of True/False
true and TRUE don't work. Use True and False
Putting elif after else
else must always come last in a chain
8. The Ternary Operator (One-Line If)
Python has a shorthand way to write simple if-else statements in one line. This is called the ternary operator or conditional expression.
value_if_true if condition else value_if_false
# Normal if-else
age = 20
if age >= 18:
status = "Adult"
else:
status = "Minor"
print(status)
# Same thing with ternary operator
age = 20
status = "Adult" if age >= 18 else "Minor"
print(status)
# Practical example
score = 75
result = "Pass" if score >= 60 else "Fail"
print(f"Result: {result}")
# ✅ Expected output:
# Adult
# Adult
# Result: Pass🔀 match / case — Python's Modern Switch Statement (Python 3.10+)
Python 3.10 introduced match/case — a cleaner way to check a value against multiple exact options. Think of it as a smarter, more readable alternative to a long elif chain when you're matching against specific values.
Old way — elif chain:
command = "quit"
if command == "start":
print("Starting...")
elif command == "stop":
print("Stopping...")
elif command == "pause":
print("Pausing...")
elif command == "quit":
print("Quitting...")
else:
print("Unknown command")command = "quit"
match command:
case "start":
print("Starting...")
case "stop":
print("Stopping...")
case "pause":
print("Pausing...")
case "quit":
print("Quitting...")
case _:
print("Unknown command")The case _: at the bottom is the wildcard — it matches anything that didn't match above (equivalent to else).
match/case with multiple values per case:
day = "Saturday"
match day:
case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday":
print("It's a weekday — get to work!")
case "Saturday" | "Sunday":
print("It's the weekend!")
case _:
print("That's not a day of the week")The | symbol means "or" inside a case — very handy for grouping related values.
9. Practical Examples
Example 1: Login Validator
# Simple login system
correct_username = "admin"
correct_password = "secret123"
# Simulated user input
entered_username = "admin"
entered_password = "secret123"
if entered_username == correct_username and entered_password == correct_password:
print("Login successful! Welcome!")
else:
print("Invalid username or password.")
# Try changing the entered values
# ✅ Expected output:
# Login successful! Welcome!Example 2: Number Classifier
# Check if a number is positive, negative, or zero
number = -5
if number > 0:
print(f"{number} is positive")
elif number < 0:
print(f"{number} is negative")
else:
print("The number is zero")
# Bonus: Check if even or odd
if number != 0:
if number % 2 == 0:
print("And it's even!")
else:
print("And it's odd!")
# ✅ Expected output:
# -5 is negative
# And it's odd!Example 3: Age Classifier
# Classify age into categories
age = 25
if age < 0:
print("Invalid age!")
elif age < 13:
print("Child")
elif age < 20:
print("Teenager")
elif age < 60:
print("Adult")
else:
print("Senior")
# Try different ages: 5, 15, 35, 70
# ✅ Expected output:
# Adult🌍 Real-World Control Flow Patterns
The same handful of patterns appear in almost every real program. Recognise them and you'll be able to write production-quality logic from day one.
Pattern 1: Input validation — reject bad data first
username = "Al"
password = "abc"
if len(username) < 3:
print("Username must be at least 3 characters")
elif len(password) < 8:
print("Password must be at least 8 characters")
elif " " in username:
print("Username cannot contain spaces")
else:
print("Account created successfully!")Validate before processing. Always check for invalid states first and give the user clear, specific feedback.
Pattern 2: Range banding — categorise a value
bmi = 22.5
if bmi < 18.5:
category = "Underweight"
advice = "Consider eating more nutritious food"
elif bmi < 25.0:
category = "Healthy weight"
advice = "Keep up your current lifestyle!"
elif bmi < 30.0:
category = "Overweight"
advice = "Consider more physical activity"
else:
category = "Obese"
advice = "Please consult a healthcare professional"
print(f"BMI: {bmi} — {category}")
print(f"Advice: {advice}")Range banding is used everywhere: credit scores, age groups, tax brackets, shipping rates, difficulty levels.
Pattern 3: Default value — use a fallback if nothing set
# User may or may not have set a display name
display_name = ""
username = "alice_99"
# Use display_name if it exists, otherwise fall back to username
name_to_show = display_name if display_name else username
print(f"Welcome, {name_to_show}!") # "Welcome, alice_99!"
# Common pattern: default settings
user_language = None
language = user_language if user_language else "English"
print(f"Language: {language}") # "Language: English"Pattern 4: Feature flags — enable/disable behaviour
# Control features with simple booleans
DEBUG_MODE = True
SHOW_ADS = False
PREMIUM_USER = True
if DEBUG_MODE:
print("[DEBUG] Application started")
if PREMIUM_USER:
print("Enjoy your ad-free experience!")
elif SHOW_ADS:
print("[Ad: Learn Python Fast!]")
message = "Premium member" if PREMIUM_USER else "Free tier"
print(f"Account: {message}")Feature flags let you turn functionality on/off with a single variable change — widely used in production software for A/B testing and gradual rollouts.
Mini-Project: Smart Shopping Discount Calculator
This project uses every control flow concept from this lesson — if/elif/else, logical operators, truthy/falsy, ternary, and nested conditions — to solve a real business problem.
- if/elif/else chains
- Logical operators (and/or)
- Truthy/falsy checks
- Ternary for labels
- Nested conditions
- Comparison operators
# Smart Shopping Discount Calculator
item_price = 85.00
quantity = 3
is_member = True
promo_code = "SAVE10"
VALID_CODES = ["SAVE10", "SUMMER20", "WELCOME5"]
# === Validate inputs ===
if item_price <= 0:
print("Error: price must be greater than zero")
elif quantity <= 0:
print("Error: quantity must be at least 1")
else:
subtotal = item_price * quantity
# === Apply bulk discount ===
if quantity >= 10:
bulk_discount = 0.15 # 15% for 10+
elif quantity >= 5:
bulk_discount = 0.10 # 10% for 5+
elif quantity >= 3:
bulk_discount = 0.05 # 5% for 3+
else:
bulk_discount = 0.00 # No bulk discount
# === Member discount ===
member_discount = 0.08 if is_member else 0.00
# === Promo code discount ===
if promo_code and promo_code in VALID_CODES:
if promo_code == "SUMMER20":
promo_discount = 0.20
elif promo_code == "SAVE10":
promo_discount = 0.10
else:
promo_discount = 0.05
else:
promo_discount = 0.00
if promo_code:
print(f"Note: '{promo_code}' is not a valid promo code")
# === Calculate total (discounts don't stack beyond 25%) ===
total_discount = min(bulk_discount + member_discount + promo_discount, 0.25)
discount_amount = subtotal * total_discount
final_price = subtotal - discount_amount
# === Display receipt ===
membership_label = "Member" if is_member else "Guest"
print("=" * 35)
print(f" RECEIPT ({membership_label})")
print("=" * 35)
print(f"Item price: £{item_price:.2f}")
print(f"Quantity: {quantity}")
print(f"Subtotal: £{subtotal:.2f}")
print(f"Bulk discount: {bulk_discount*100:.0f}%")
print(f"Member discount:{member_discount*100:.0f}%")
print(f"Promo discount: {promo_discount*100:.0f}%")
print(f"Total saved: £{discount_amount:.2f} ({total_discount*100:.0f}%)")
print(f"TOTAL: £{final_price:.2f}")
print("=" * 35)Can you add a check that prints "Free delivery!" if final_price >= 50? What about adding a loyalty points calculation: 1 point per £1 spent, but double points for members?
💡 Thinking in Conditions: How Developers Design Logic
Writing correct if/elif/else logic is a skill. Here's the thinking process professionals use when turning requirements into code.
Step 1: List all possible outcomes
Before writing a single line, ask: "What are all the different things that could happen?" Write them in plain English first.
# Requirement: categorise a user's subscription
# Outcomes:
# - No subscription → show free tier
# - Basic plan → show basic features
# - Pro plan → show pro features + no ads
# - Admin → show all features + admin panelStep 2: Identify edge cases
What happens with invalid, unexpected, or extreme values? Always ask:
- What if the input is empty or None?
- What if a number is negative or zero?
- What if the user hasn't set something yet?
- What's the maximum/minimum allowed value?
Step 3: Decide the order
For range checks: put the most specific condition first. For validation: check the most likely failure first. For priority: most important condition at the top.
Step 4: Test with examples
Manually trace through your code with at least 3 test values — one for each branch, plus one edge case. Ask: "What value do I need to reach the else?" If you can't answer, your logic might have a gap.
Summary: Quick Reference
| Concept | What It Does | Syntax |
|---|---|---|
| if | Runs code if condition is True | if x > 0: |
| else | Runs if the if condition is False | else: |
| elif | Checks another condition | elif x > 5: |
| and | Both conditions must be True | if a and b: |
| or | At least one must be True | if a or b: |
| not | Reverses the condition | if not a: |
| Ternary | One-line if-else | x if cond else y |
🎯 Mini Challenge: Parcel Postage Calculator
No blanks this time — just a brief and an empty space. Work out the postage for a parcel using the rules below. Everything you need you learned in this lesson: an if/elif/else chain for the weight bands, and separate if statements for the surcharges that stack on top.
Stuck? Look back at the cinema ticket worked example — it has exactly this shape: one chain that picks a band, then separate ifs that adjust the running total.
# 🎯 MINI-CHALLENGE: parcel postage calculator
weight_kg = 6.5
distance_km = 250
is_express = True
# 1. Create a variable "total" starting at 3.99 (the base cost)
#
# 2. Weight surcharge - ONE if/elif/else chain:
# over 10 kg -> add 5.00
# over 2 kg -> add 2.00
# otherwise -> add nothing
#
# 3. A separate if: when distance_km is more than 100, add 4.50
#
# 4. A separate if: when is_express is True, multiply total by 2
#
# 5. Print exactly two lines:
# f"Parcel: {weight_kg} kg, {distance_km} km"
# f"Total: £{total:.2f}"
# your code here
# ✅ Expected output:
# Parcel: 6.5 kg, 250 km
# Total: £20.98
#
# Watch the order in step 2: if you test "over 2 kg" before "over 10 kg",
# a 12 kg parcel matches the wrong band and you undercharge by 3.00.What's Next?
Now that you can make decisions, it's time to learn about loops! Loops let you repeat code multiple times, which is essential for:
- Processing lists of items
- Running code until a condition changes
- Creating interactive programs
Lesson complete — your programs can now make decisions!
You've mastered if, elif, else, logical operators, nested conditions, and the ternary expression. Your programs are no longer just top-to-bottom scripts — they can respond to different situations.
Practice quiz
In an if/elif/elif chain, how many branches run when several conditions are True?
- All matching branches
- Only the last True branch
- Only the first True branch
- None of them
Answer: Only the first True branch. Python checks top to bottom and runs only the first True branch, skipping the rest.
When using >= range checks like grades, which condition should come first?
- The highest / most specific threshold
- The lowest threshold
- The else branch
- Order does not matter
Answer: The highest / most specific threshold. With >= ranges, check the highest threshold first, or a broad early condition catches everything.
What does the else clause do in an if/elif/else chain?
- Checks one more condition
- Always runs
- Runs before the if
- Runs only when none of the above conditions were True
Answer: Runs only when none of the above conditions were True. else has no condition; it runs as a fallback when no earlier condition was True.
Which of these is a FALSY value in Python?
- "0" (the string)
- [] (empty list)
- [0] (list with one item)
- -5
Answer: [] (empty list). An empty list is falsy. A non-empty string "0", a non-empty list [0], and -5 are all truthy.
What does the ternary expression "Adult" if age >= 18 else "Minor" return when age is 20?
- "Adult"
- "Minor"
- True
- 20
Answer: "Adult". Since 20 >= 18 is True, the expression returns "Adult".
What is the difference between = and == in a condition?
- They are interchangeable
- == assigns; = compares
- = assigns a value; == compares for equality
- Both compare values
Answer: = assigns a value; == compares for equality. = assigns a value to a variable; == tests whether two values are equal.
Which is the recommended (PEP 8) way to check for None?
- if value == None:
- if value is None:
- if value = None:
- if not value:
Answer: if value is None:. PEP 8 recommends 'is None' — it's more readable and technically correct.
What does the | symbol mean inside a match/case pattern, e.g. case "Saturday" | "Sunday":?
- Bitwise OR of bytes
- A pipe to another function
- String concatenation
- 'or' — the case matches any of the listed values
Answer: 'or' — the case matches any of the listed values. Inside a case, | means 'or', so the case matches any of the listed values.
What does case _: do in a match statement?
- Matches only underscores
- Acts as the wildcard / default, like else
- Raises an error
- Matches nothing
Answer: Acts as the wildcard / default, like else. case _: is the wildcard that matches anything not matched above, equivalent to else.
What is the key idea behind a guard clause (early return pattern)?
- Nest every condition deeply
- Always use match/case
- Reject bad cases early and return, keeping the main logic flat
- Avoid using else
Answer: Reject bad cases early and return, keeping the main logic flat. Guard clauses check for invalid cases first and exit early, keeping the happy path flat and readable.
Continue this course
- Previous: Operators and Expressions
- Next: Loops - For and While — Repeat actions automatically with for loops and while loops
- Quick reference: Python cheat sheet › Control Flow