Python Conditional Statements: The Complete Beginner's Guide

Every useful program makes decisions. This chapter turns comparisons and booleans into real branching logic with \`if/elif/else\`, readable guard clauses, nested conditions, ternary expressions, and \`match\` for Python 3.10+ multi-branch flows.

Chapter 8 of 20 · Beginner · 40 min · Python Programming Course

Every useful program makes decisions. Show this page if the user is logged in. Charge this price if the customer has a premium account. Send the alert if the temperature exceeds the threshold. Approve the loan if income is above the minimum and age is over eighteen.

Decision-making in Python is handled by conditional statements — code that evaluates a condition and executes different instructions depending on whether that condition is True or False.

You already have everything you need to write powerful conditions: comparison operators from Day 3, boolean values from Day 2, and rich data from the dictionaries, lists, and sets you built in Days 5 through 7. This chapter puts all of it together into programs that actually think.

What You Will Learn in This Chapter

By the end of this tutorial you will be able to:

  • Write if, elif, and else statements correctly
  • Combine multiple conditions using and, or, and not
  • Write nested conditionals for multi-level decisions
  • Use ternary expressions for clean one-line conditionals
  • Apply truthy and falsy evaluation to write concise conditions
  • Use match statements for clean multi-branch logic (Python 3.10+)
  • Recognise and fix the most common conditional mistakes
  • Write conditions that are readable, not just correct

Estimated time: 40 minutes reading + 20 minutes practice

The if Statement — The Foundation of Every Decision

An if statement evaluates a condition. If the condition is True, the indented block runs. If it is False, Python skips it entirely:

temperature = 38

if temperature > 35:
    print("It is very hot today")
    print("Stay hydrated")

print("This always runs")

Output:

It is very hot today
Stay hydrated
This always runs

Two things to notice immediately:

  • The colon after the condition is required. if temperature > 35: — forgetting the colon is a SyntaxError.
  • Indentation defines the block. Everything indented under the if is part of its block. The moment indentation returns to the original level, the block ends. Python does not use curly braces like C++ or Java — indentation is the syntax.
score = 45

if score >= 50:
    print("Passed")      # only runs if score >= 50
    print("Well done")   # also only runs if score >= 50

print("Exam complete")   # always runs — outside the if block

if/else — Handling Both Outcomes

else provides a block that runs when the if condition is False:

age = 16

if age >= 18:
    print("You can vote")
else:
    print("You cannot vote yet")

Output:

You cannot vote yet

Exactly one of the two blocks will run — never both, never neither. This is guaranteed.

balance = 1200
withdrawal = 1500

if withdrawal <= balance:
    balance -= withdrawal
    print(f"Withdrawal successful. New balance: {balance}")
else:
    print(f"Insufficient funds. Balance: {balance}, Requested: {withdrawal}")

Output:

Insufficient funds. Balance: 1200, Requested: 1500

elif — Multiple Branches

elif (short for "else if") lets you check multiple conditions in sequence. Python evaluates them top to bottom and executes the first block whose condition is True. All remaining branches are skipped:

score = 83

if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 70:
    grade = "C"
elif score >= 60:
    grade = "D"
else:
    grade = "F"

print(f"Score: {score} → Grade: {grade}")

Output:

Score: 83 → Grade: B

Python checked score >= 90 (False), then score >= 80 (True) — found a match, ran that block, and skipped all the remaining elif and else branches.

The Order of elif Matters

Conditions are checked sequentially. If an earlier condition is too broad, it catches cases that should have fallen through to a later branch:

score = 95

# Wrong order — first condition catches everything >= 60
if score >= 60:
    grade = "D"    # score 95 lands here — wrong
elif score >= 70:
    grade = "C"
elif score >= 80:
    grade = "B"
elif score >= 90:
    grade = "A"

print(grade)    # D — incorrect
# Correct order — most restrictive condition first
if score >= 90:
    grade = "A"    # score 95 correctly lands here
elif score >= 80:
    grade = "B"
elif score >= 70:
    grade = "C"
elif score >= 60:
    grade = "D"
else:
    grade = "F"

print(grade)    # A — correct

Rule: when conditions overlap, put the most restrictive (most specific) condition first.

Combining Conditions With and, or, not

You covered logical operators in Day 3. Here is how they appear in real conditional statements.

and — Both Conditions Must Be True

age = 25
has_licence = True
has_insurance = True

if age >= 18 and has_licence and has_insurance:
    print("You can drive")
else:
    print("You cannot drive")
# Output: You can drive
temperature = 28
humidity = 55

if temperature >= 20 and temperature <= 30 and humidity < 70:
    print("Perfect weather for outdoor exercise")
else:
    print("Consider indoor exercise today")
# Output: Perfect weather for outdoor exercise

or — At Least One Condition Must Be True

day = "Saturday"

if day == "Saturday" or day == "Sunday":
    print("Weekend — no work")
else:
    print("Weekday — work day")
# Output: Weekend — no work
user_role = "moderator"

if user_role == "admin" or user_role == "moderator":
    print("You can delete posts")
else:
    print("You cannot delete posts")

not — Reverses the Boolean

is_logged_in = False

if not is_logged_in:
    print("Please log in to continue")
# Output: Please log in to continue
banned_users = {"troll_99", "spammer_42"}
username = "alice"

if username not in banned_users:
    print(f"Welcome, {username}")
else:
    print("Access denied")
# Output: Welcome, alice

Combining All Three

age = 22
has_ticket = True
is_banned = False

if age >= 18 and has_ticket and not is_banned:
    print("Entry granted")
else:
    print("Entry denied")
# Output: Entry granted

Use parentheses to make complex conditions explicit:

# Ambiguous — what groups together?
if a > 0 and b > 0 or c > 0:
    pass

# Clear — intent is obvious
if (a > 0 and b > 0) or c > 0:
    pass

Nested Conditionals — Decisions Inside Decisions

A nested conditional is an if statement inside another if block. Use this when the inner decision only makes sense after the outer condition is confirmed:

user_type = "premium"
purchase_amount = 150

if user_type == "premium":
    if purchase_amount >= 100:
        discount = 0.20
        print(f"Premium + large order: 20% discount")
    else:
        discount = 0.10
        print(f"Premium + small order: 10% discount")
else:
    if purchase_amount >= 100:
        discount = 0.05
        print(f"Standard + large order: 5% discount")
    else:
        discount = 0.00
        print(f"Standard + small order: no discount")

print(f"Final discount: {discount * 100:.0f}%")

Output:

Premium + large order: 20% discount
Final discount: 20%

When to Flatten Nested Conditions

Deeply nested conditions become hard to read quickly. When you find yourself nesting three or more levels deep, flattening with and is usually cleaner:

# Nested — harder to follow
if user_type == "premium":
    if age >= 18:
        if not is_banned:
            print("Access granted")

# Flat — same logic, much easier to read
if user_type == "premium" and age >= 18 and not is_banned:
    print("Access granted")

The flat version is preferred unless the inner decision needs its own else branch that is meaningfully different from the outer one.

Truthy and Falsy Values — Writing Cleaner Conditions

In Python, every value has an implicit boolean interpretation. You do not always need == True or == False — Python evaluates the value directly.

Falsy values — these evaluate to False in a condition:

False
None
0          # integer zero
0.0        # float zero
""         # empty string
[]         # empty list
{}         # empty dict
()         # empty tuple
set()      # empty set

Everything else is truthy — evaluates to True.

name = "Alice"
items = [1, 2, 3]
count = 0
message = ""

# Verbose — unnecessary
if name != "":
    print("Name provided")

# Pythonic — uses truthy evaluation
if name:
    print("Name provided")
# Check if a list has items
cart = ["laptop", "mouse"]

if cart:
    print(f"Cart has {len(cart)} items")
else:
    print("Cart is empty")
# Output: Cart has 2 items
# Check if a value exists
user_input = "Mumbai".strip()

if user_input:
    city = user_input
else:
    city = "Unknown"

The not shortcut for empty checks:

errors = []

if not errors:
    print("No errors found")    # runs because [] is falsy, not errors is True

This pattern appears constantly in real Python code. Learn to read it naturally.

Ternary Expressions — One-Line Conditionals

A ternary expression (also called a conditional expression) assigns one of two values based on a condition, all in a single line:

# Standard syntax
value_if_true if condition else value_if_false
age = 20
status = "adult" if age >= 18 else "minor"
print(status)    # adult
score = 73
grade = "Pass" if score >= 60 else "Fail"
print(grade)    # Pass
# Inside an f-string
is_enrolled = True
print(f"Status: {'Active' if is_enrolled else 'Inactive'}")
# Output: Status: Active

When to Use Ternary Expressions

Use them for simple, readable one-liners where both outcomes are clear. Avoid them when the condition or either value is complex — a regular if/else is always clearer when the logic needs to breathe:

# Good — simple and readable
label = "even" if number % 2 == 0 else "odd"

# Avoid — too complex for one line, use if/else instead
result = process_a(x) if x > 0 and y < 100 and not flag else process_b(x, y, z)

Chained Comparisons — A Python Exclusive

Python supports chaining comparison operators in a way most other languages do not. This checks whether a value falls within a range cleanly:

age = 25

# Other languages require this
if age >= 18 and age <= 65:
    print("Working age")

# Python allows this — equivalent and more readable
if 18 <= age <= 65:
    print("Working age")
score = 83

if 80 <= score < 90:
    print("Grade B")

temperature = 22
if 15 < temperature < 30:
    print("Comfortable temperature")

Chained comparisons read exactly like mathematical notation and are unambiguous. Use them whenever you are checking ranges.

The match Statement (Python 3.10+) — Clean Multi-Branch Logic

Python 3.10 introduced match — a structural pattern matching statement that handles multiple specific value checks more cleanly than long elif chains:

command = "quit"

match command:
    case "start":
        print("Starting the application")
    case "stop":
        print("Stopping the application")
    case "quit":
        print("Quitting and saving")
    case "help":
        print("Showing help menu")
    case _:
        print(f"Unknown command: {command}")

Output:

Quitting and saving

The case _: is the default — equivalent to else. It matches anything not caught by earlier cases.

# Match with multiple values per case
day = "Saturday"

match day:
    case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday":
        print("Weekday")
    case "Saturday" | "Sunday":
        print("Weekend")
    case _:
        print("Invalid day")
# Output: Weekend

match vs elif: use match when checking one variable against specific literal values — it is cleaner and more readable. Use if/elif when conditions involve ranges, comparisons, or multiple variables.

Real-World Conditional Patterns

These are the patterns that appear most frequently in actual Python programs.

Pattern 1: Input Validation

def validate_age(age_input):
    if not isinstance(age_input, int):
        return "Error: age must be an integer"
    if age_input < 0:
        return "Error: age cannot be negative"
    if age_input > 150:
        return "Error: age is unrealistically high"
    return f"Valid age: {age_input}"

print(validate_age(25))     # Valid age: 25
print(validate_age(-5))     # Error: age cannot be negative
print(validate_age("old"))  # Error: age must be an integer

Pattern 2: Early Return — The Guard Clause

Instead of nesting logic deeper and deeper, return early when a condition fails. This flattens the code significantly:

# Deeply nested — hard to follow
def process_order(user, cart, payment):
    if user is not None:
        if len(cart) > 0:
            if payment["valid"]:
                # actual processing logic buried 3 levels deep
                return "Order processed"
            else:
                return "Invalid payment"
        else:
            return "Cart is empty"
    else:
        return "User not found"

# Guard clauses — same logic, much more readable
def process_order(user, cart, payment):
    if user is None:
        return "User not found"
    if len(cart) == 0:
        return "Cart is empty"
    if not payment["valid"]:
        return "Invalid payment"

    # actual processing logic at the top level, unobstructed
    return "Order processed"

Guard clauses are one of the most impactful readability improvements you can make to Python functions. You will see this pattern in every professional codebase.

Pattern 3: Membership Testing

VALID_CATEGORIES = {"electronics", "clothing", "food", "books", "sports"}

category = "electronics".strip().lower()

if category in VALID_CATEGORIES:
    print(f"Valid category: {category}")
else:
    print(f"Invalid category. Choose from: {', '.join(sorted(VALID_CATEGORIES))}")

Pattern 4: Status-Based Routing

def handle_response(status_code):
    if 200 <= status_code < 300:
        return "Success"
    elif 300 <= status_code < 400:
        return "Redirect"
    elif 400 <= status_code < 500:
        return "Client error"
    elif 500 <= status_code < 600:
        return "Server error"
    else:
        return "Unknown status"

print(handle_response(200))    # Success
print(handle_response(404))    # Client error
print(handle_response(500))    # Server error

A Complete Working Program

Here is a loan eligibility checker that uses every conditional concept from this chapter in a realistic scenario:

# Loan eligibility checker
def check_loan_eligibility(applicant):
    name = applicant["name"]
    age = applicant["age"]
    income = applicant["monthly_income"]
    credit_score = applicant["credit_score"]
    existing_loans = applicant["existing_loans"]
    employment = applicant["employment_type"]

    # Guard clauses — reject immediately if hard disqualifiers
    if age < 21 or age > 65:
        return name, "Rejected", "Age must be between 21 and 65"

    if employment == "unemployed":
        return name, "Rejected", "Must be employed"

    if credit_score < 600:
        return name, "Rejected", f"Credit score {credit_score} below minimum 600"

    # Determine loan tier
    if credit_score >= 750 and income >= 80000 and existing_loans == 0:
        tier = "Premium"
        max_loan = income * 60
        interest_rate = 7.5
    elif credit_score >= 700 and income >= 50000 and existing_loans <= 1:
        tier = "Standard"
        max_loan = income * 40
        interest_rate = 10.5
    elif credit_score >= 650 and income >= 30000:
        tier = "Basic"
        max_loan = income * 20
        interest_rate = 14.0
    else:
        return name, "Rejected", "Does not meet minimum combined criteria"

    return name, "Approved", f"{tier} tier | Max loan: ₹{max_loan:,} | Rate: {interest_rate}%"


# Test applicants
applicants = [
    {"name": "Priya Sharma",  "age": 32, "monthly_income": 90000,
     "credit_score": 780, "existing_loans": 0, "employment_type": "salaried"},
    {"name": "Arjun Mehta",   "age": 19, "monthly_income": 25000,
     "credit_score": 680, "existing_loans": 0, "employment_type": "salaried"},
    {"name": "Cleo Park",     "age": 45, "monthly_income": 60000,
     "credit_score": 720, "existing_loans": 1, "employment_type": "salaried"},
    {"name": "Ravi Kumar",    "age": 38, "monthly_income": 35000,
     "credit_score": 590, "existing_loans": 2, "employment_type": "self-employed"},
    {"name": "Maya Torres",   "age": 28, "monthly_income": 45000,
     "credit_score": 660, "existing_loans": 0, "employment_type": "unemployed"},
]

print(f"{'Name':<15} {'Decision':<10} {'Details'}")
print("-" * 70)
for applicant in applicants:
    name, decision, details = check_loan_eligibility(applicant)
    print(f"{name:<15} {decision:<10} {details}")

Output:

Name            Decision   Details
----------------------------------------------------------------------
Priya Sharma    Approved   Premium tier | Max loan: ₹5,400,000 | Rate: 7.5%
Arjun Mehta     Rejected   Age must be between 21 and 65
Cleo Park       Approved   Standard tier | Max loan: ₹2,400,000 | Rate: 10.5%
Ravi Kumar      Rejected   Credit score 590 below minimum 600
Maya Torres     Rejected   Must be employed

Every concept from this chapter appears here — guard clauses, elif chains, and conditions, range checks, and a clean top-to-bottom decision structure.

5 Conditional Mistakes Every Beginner Makes

Mistake 1: Using = instead of == in conditions

age = 18

# if age = 18:       # SyntaxError in Python 3
#     print("Adult")

if age == 18:      # correct
    print("Adult")

Mistake 2: Wrong elif order catches the wrong branch

score = 95

# Wrong — score 95 matches >= 60 first, gets grade D
if score >= 60:
    grade = "D"
elif score >= 90:
    grade = "A"    # never reached for score 95

# Correct — most restrictive first
if score >= 90:
    grade = "A"
elif score >= 60:
    grade = "D"

Mistake 3: Comparing to True or False explicitly

is_active = True

if is_active == True:    # works but verbose
    print("Active")

if is_active:            # Pythonic — same result
    print("Active")

if not is_active:        # cleaner than is_active == False
    print("Inactive")

Mistake 4: Forgetting the colon

# if age >= 18        # SyntaxError: expected ':'
#     print("Adult")

if age >= 18:       # correct
    print("Adult")

Mistake 5: Misunderstanding and vs or in exclusion logic

day = "Saturday"

# Wrong — this can never be True
# No single value can equal both "Saturday" AND "Sunday" simultaneously
if day == "Saturday" and day == "Sunday":
    print("Weekend")    # never prints

# Correct
if day == "Saturday" or day == "Sunday":
    print("Weekend")

# Even cleaner
if day in ("Saturday", "Sunday"):
    print("Weekend")

The and vs or confusion when checking one variable against multiple values is extremely common. When you want "matches any of these values", use in with a tuple or set — it is cleaner than multiple or conditions.

Practice: Conditional Statement Exercises

Exercise 1: Grade classifier

Write a function classify_grade(score) that returns "A" for 90+, "B" for 80-89, "C" for 70-79, "D" for 60-69, and "F" below 60. Test it with scores 95, 82, 71, 65, and 45.

Exercise 2: FizzBuzz

Write a program that checks a number and prints "FizzBuzz" if divisible by both 3 and 5, "Fizz" if divisible by 3 only, "Buzz" if divisible by 5 only, or the number itself otherwise. Test with 15, 9, 10, and 7.

Exercise 3: Login validator

Write a function that takes a username and password. Return "Access granted" only if username is not empty, password is at least 8 characters, and username is not in a banned list {"admin", "root", "test"}. Return a specific error message for each failure case.

Exercise 4: Shipping cost calculator

Write a function that calculates shipping cost based on weight and membership. Members pay half price. Weights up to 1kg cost ₹50, 1-5kg cost ₹120, 5-10kg cost ₹200, and above 10kg cost ₹350. Test with several combinations.

Exercise 5: Leap year checker

A year is a leap year if it is divisible by 4, except century years (divisible by 100) are not leap years unless also divisible by 400. Write a function is_leap_year(year) that returns True or False. Test with 2000, 1900, 2024, and 2023.

See all Python practice exercises with solutions

For all topics, see Python exercises.

What Comes Next — Day 9: Loops and Iteration

Conditionals let your program choose a path. Loops let your program repeat a path — processing every item in a list, running until a condition changes, iterating through a dictionary. With the data structures from Days 5-7 and the conditional logic from today, loops in Day 9 will let you build programs that handle real collections of data automatically.

Day 9 covers:

  • for loops — iterating over sequences
  • while loops — repeating until a condition is false
  • range() — generating number sequences
  • enumerate() — loops with index awareness
  • break, continue, and else on loops
  • Nested loops for 2D data

Continue to Day 9: Loops and Iteration

Chapter navigation

Frequently asked questions: Conditional statements

What are conditional statements in Python?

Conditional statements are code structures that execute different blocks depending on whether a condition evaluates to True or False. Python uses if for the primary condition, elif for additional conditions, and else for the fallback when no condition matches. They are the fundamental mechanism for decision-making in any program.

What is the difference between if, elif, and else in Python?

if checks the first condition. elif checks additional conditions only if all previous conditions were False — you can have as many elif branches as needed. else runs when no if or elif condition matched. Exactly one branch runs per if/elif/else chain — never more than one, never zero if else is present.

Why does the order of elif conditions matter in Python?

Python evaluates conditions top to bottom and executes the first matching branch, skipping all the rest. If a broader condition appears before a more specific one, the specific case is never reached. For overlapping range checks, always put the most restrictive condition first.

What is a ternary expression in Python?

A ternary expression is a one-line conditional that assigns one of two values: value_if_true if condition else value_if_false. It is equivalent to a two-branch if/else but written in a single expression. Use it for simple, readable assignments — avoid it when the condition or either value is complex.

What are truthy and falsy values in Python?

Every Python value has an implicit boolean interpretation. Falsy values evaluate to False in conditions: False, None, 0, 0.0, "", [], {}, (), and set(). Everything else is truthy. This lets you write if name: instead of if name != "" and if cart: instead of if len(cart) > 0.

What is a guard clause in Python?

A guard clause is an early return or raise at the top of a function that handles error or edge cases immediately, before the main logic. Instead of nesting the happy path inside multiple if blocks, guard clauses reject invalid inputs at the top and leave the main logic flat and readable. This pattern is widely used in professional Python code.

What is the difference between and and or in Python conditions?

and requires every condition to be True — one False makes the whole expression False. or requires at least one condition to be True — only returns False when every condition is False. A common mistake is using and when checking one variable against multiple values: day == "Saturday" and day == "Sunday" can never be True. Use or or in for multiple value checks.

What is the match statement in Python?

match was introduced in Python 3.10 as a structural pattern matching statement. It checks one expression against multiple specific patterns — cleaner than a long elif chain when comparing a variable against literal values. The case _: at the end serves as the default fallback, equivalent to else.