Control Flow: if, elif, else
Control Flow: if, elif, else
Control flow is what makes programs intelligent. Without it, code just executes line by line. With it, your program can make decisions, react to different inputs, and branch into completely different paths.
Basic if/elif/else
score = 78
if score >= 90:
print("Grade: A")
elif score >= 80:
print("Grade: B")
elif score >= 70:
print("Grade: C")
elif score >= 60:
print("Grade: D")
else:
print("Grade: F")
# Output: Grade: C
Python uses indentation (4 spaces) to define blocks — no curly braces. This is not optional formatting; it's part of the syntax.
Truthiness: What Evaluates to False?
In Python, many values besides False are "falsy":
# These all evaluate to False:
bool(0) # False
bool(0.0) # False
bool("") # False — empty string
bool([]) # False — empty list
bool({}) # False — empty dict
bool(None) # False
# These all evaluate to True:
bool(1) # True
bool(-1) # True — any non-zero number
bool("hello") # True
bool([0]) # True — non-empty list (even if it contains 0)
This means you can write very Pythonic conditions:
name = input("Enter your name: ")
# Instead of: if name != "":
if name:
print(f"Hello, {name}!")
else:
print("No name provided.")
# Instead of: if len(items) > 0:
items = []
if items:
print(f"Processing {len(items)} items")
else:
print("Nothing to process")
Comparison and Logical Operators
# Comparison
x = 10
print(x > 5) # True
print(x == 10) # True
print(x != 5) # True
print(x >= 10) # True
# Logical operators
age = 25
has_id = True
if age >= 18 and has_id:
print("Entry allowed")
if age < 18 or not has_id:
print("Entry denied")
# Chaining comparisons (Python-specific, very readable)
temperature = 22
if 18 <= temperature <= 26:
print("Comfortable temperature")
The Ternary Operator
Python's one-line conditional:
# Syntax: value_if_true if condition else value_if_false
age = 20
status = "adult" if age >= 18 else "minor"
print(status) # "adult"
# Another example
score = 75
result = "pass" if score >= 60 else "fail"
Use it sparingly — for simple cases only. If the logic is complex, use a regular if/else block for readability.
Nested if Statements
def classify_number(n):
if n > 0:
if n % 2 == 0:
return "positive even"
else:
return "positive odd"
elif n < 0:
return "negative"
else:
return "zero"
print(classify_number(4)) # positive even
print(classify_number(-3)) # negative
print(classify_number(0)) # zero
Avoid deep nesting — more than 2-3 levels makes code hard to read. Use early returns instead:
# Deeply nested — hard to read
def process_order(user, order):
if user is not None:
if user.is_active:
if order is not None:
if order.total > 0:
# actual logic...
return "processed"
# Better: early returns (guard clauses)
def process_order(user, order):
if user is None:
return "error: no user"
if not user.is_active:
return "error: inactive user"
if order is None:
return "error: no order"
if order.total <= 0:
return "error: invalid total"
# actual logic with no nesting
return "processed"
Python 3.10+ Match/Case Statement
Python's match/case is similar to switch statements in other languages but more powerful:
command = "quit"
match command:
case "quit":
print("Exiting...")
case "help":
print("Commands: quit, help, start")
case "start":
print("Starting application...")
case _: # _ is the default/wildcard
print(f"Unknown command: {command}")
Match with patterns:
point = (0, 1)
match point:
case (0, 0):
print("Origin")
case (x, 0):
print(f"On x-axis at {x}")
case (0, y):
print(f"On y-axis at {y}")
case (x, y):
print(f"Point at ({x}, {y})")
Real-World Example: Login System
def authenticate(username, password, users_db):
"""Authenticate a user and return their role."""
# Guard clauses first
if not username or not password:
return None, "Username and password required"
if username not in users_db:
return None, "Invalid credentials" # Don't say "user not found" — security
user = users_db[username]
if not user['active']:
return None, "Account is disabled"
if user['password'] != hash_password(password):
return None, "Invalid credentials"
return user['role'], "Login successful"
users_db = {
"alice": {"password": "hashed_pw_1", "role": "admin", "active": True},
"bob": {"password": "hashed_pw_2", "role": "user", "active": True},
"carol": {"password": "hashed_pw_3", "role": "user", "active": False},
}
role, message = authenticate("alice", "correctpassword", users_db)
print(f"Role: {role}, Message: {message}")
Key Principles
- Use
if name:notif name != ""— Pythonic truthiness checks are cleaner - Use early returns to avoid deep nesting
- Prefer
elifover nestedifwhen conditions are mutually exclusive - Ternary for simple one-liners, regular
if/elsefor anything else
Next lesson: Loops — mastering for, while, and Python's powerful comprehensions.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises