Lesson 4 • Beginner
Control Flow: Making Decisions in Python
Learn how to make your programs smart by having them make decisions based on conditions.
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
Real-world analogy:
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.
# Syntax:
if condition:
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) |
Try It: Basic if Statement
Change the age value and observe which lines print
# 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!2. The if-else Statement
What if you want to do something different when the condition is False? Use else to specify an alternative action.
# Syntax:
if condition:
code if True
else:
code if False
If condition is True:
Run the first block, skip the else block
If condition is False:
Skip the first block, run the else block
Try It: if-else Statement
See how else provides an alternative path
# 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 353. The if-elif-else Chain
When you have more than two possibilities, use elif(short for "else if") to check multiple conditions.
# Syntax:
if condition1:
code for condition1
elif condition2:
code for condition2
elif condition3:
code for condition3
else:
code if none are True
Try It: Grading System
Classic example of multiple conditions
# 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, 554. 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 |
= (assignment) with == (comparison)!x = 5 assigns the value 5 to x.x == 5 checks if x equals 5.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 |
Try It: Logical Operators
Combine multiple conditions
# 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!⚡ 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 zero0.0— the float zero""— empty string[]— empty listNone— no valueFalse— 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 listTrue— boolean True
Practical truthy/falsy patterns:
# 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")is None not == None when checking for None. Python's style guide (PEP 8) specifically recommends if value is None over if value == None — it's both more readable and technically more correct.6. Nested If Statements
You can put an if statement inside another if statement. This is called nesting and is useful for complex decisions.
Try It: Nested Conditions
Multiple layers of decision making
# 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 Trueand instead:if age >= 18 and has_id: does the same thing!🛡️ 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.
Correct
if age >= 18:
print("Adult")
print("Can vote")Wrong
if age >= 18:
print("Adult") # Error!Common Indentation Errors:
IndentationError: expected an indented block- Missing indentation after colonIndentationError: unexpected indent- Random indentation where not neededIndentationError: unindent does not match- Mixing tabs and spaces
Common Mistakes to Avoid
Using = instead of ==
if x = 5: is wrong. Use if x == 5:
Forgetting the colon :
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.
# Syntax:
value_if_true if condition else value_if_false
Try It: Ternary Operator
Write compact conditional expressions
# 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}")🔀 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")New way — match/case:
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.
python --version. If you're on 3.9 or earlier, use elif chains instead. Both work — match/case is just cleaner for exact value matching.9. Practical Examples
Example 1: Login Validator
Login Validator
Validate username and password
# 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 valuesExample 2: Number Classifier
Number Classifier
Classify numbers by sign and parity
# 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!")Example 3: Age Classifier
Age Classifier
Categorize by age group
# 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🌍 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.
Concepts used:
- ✓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)Challenge — extend it:
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 panel
Step 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.
if block does, rename your variables or add a comment. Clear conditions prevent bugs more than clever ones.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 |
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 4 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.
🚀 Up next: Loops — make Python repeat tasks automatically instead of copy-pasting code.
Sign up for free to track which lessons you've completed and get learning reminders.