Python & AI Tutorials Logo
Python Programming

8. Making Decisions with if Statements

In the programs we've written so far, Python executes every line of code from top to bottom, one statement after another. But real-world programs need to make decisions—to execute different code depending on different conditions. Should we display an error message? Should we calculate a discount? Should we ask for input again? The answer depends on the situation.

Conditional statements let your programs make these decisions. They allow Python to execute certain blocks of code only when specific conditions are true, and skip them otherwise. This chapter introduces Python's if statement and its variations, which form the foundation of decision-making in your programs.

By mastering conditional statements, you'll be able to write programs that respond intelligently to user input, handle different scenarios appropriately, and solve problems that require logical reasoning.

8.1) Simple if Statements

The most basic form of decision-making in Python is the simple if statement. It tells Python: "If this condition is true, execute this block of code. Otherwise, skip it and continue."

8.1.1) The Structure of an if Statement

Here's the basic syntax of an if statement:

python
if condition:
    # Code to execute if condition is True
    statement1
    statement2
    # ... more statements

Let's break down each part:

  1. The if keyword: This starts the conditional statement
  2. The condition: A boolean expression that evaluates to True or False (from Chapter 7)
  3. The colon (:): This is required and marks the end of the condition line
  4. The indented code block: All statements indented under the if are executed only when the condition is True

Indentation is critical in Python. The indented lines form a code block that belongs to the if statement. Python uses indentation (typically 4 spaces) to determine which statements are part of the conditional block.

Here's a simple example:

python
# temperature_check.py
temperature = 30
 
if temperature > 25:
    print("It's a warm day!")
    print("Consider wearing light clothing.")
 
print("Have a great day!")  # This always executes

Output:

It's a warm day!
Consider wearing light clothing.
Have a great day!

In this example:

  • The condition temperature > 25 evaluates to True (since 30 > 25)
  • Both indented print() statements execute because they're part of the if block
  • The final print() statement always executes because it's not indented—it's not part of the if block

Now let's see what happens when the condition is False:

python
# temperature_check_cool.py
temperature = 18
 
if temperature > 25:
    print("It's a warm day!")
    print("Consider wearing light clothing.")
 
print("Have a great day!")  # This always executes

Output:

Have a great day!

This time:

  • The condition temperature > 25 evaluates to False (since 18 is not greater than 25)
  • Both indented statements are skipped entirely
  • Only the final print() executes because it's outside the if block

Yes

No

Start

Is condition True?

Execute indented block

Skip indented block

Continue with rest of program

End

8.1.2) Using Conditions from Chapter 7

Any boolean expression from Chapter 7 can be used as a condition in an if statement. This includes:

Comparison operators:

python
# voting_eligibility.py
age = 16
 
if age >= 18:
    print("You are eligible to vote.")
# Nothing prints because 16 >= 18 is False
 
score = 85
 
if score >= 60:
    print("You passed the exam!")  # Output: You passed the exam!

Membership tests with in and not in:

python
# user_access.py
username = "alice"
banned_users = ["bob", "charlie", "dave"]
 
if username not in banned_users:
    print(f"Welcome, {username}!")  # Output: Welcome, alice!
 
favorite_color = "blue"
 
if "u" in favorite_color:
    print("Your favorite color contains the letter 'u'.")  # Output: Your favorite color contains the letter 'u'.

Direct boolean values:

python
# weather_check.py
is_raining = True
 
if is_raining:
    print("Don't forget your umbrella!")  # Output: Don't forget your umbrella!

Truthiness and falsiness (from Chapter 7.4):

python
# name_input.py
user_input = input("Enter your name: ")
 
if user_input:  # Empty string is falsy, non-empty is truthy
    print(f"Hello, {user_input}!")
else:
    print("You didn't enter a name.")

8.1.3) Multiple Statements in the if Block

You can include as many statements as you need in an if block. All indented statements under the if line belong to that block:

python
# bank_withdrawal.py
balance = 1500
withdrawal = 200
 
if withdrawal <= balance:
    balance = balance - withdrawal  # Subtract withdrawal from balance
    print(f"Withdrawal successful!")
    print(f"Your new balance is: ${balance}")
    print("Thank you for your transaction.")
 
print("Transaction complete.")  # Always executes

Output:

Withdrawal successful!
Your new balance is: $1300
Thank you for your transaction.
Transaction complete.

All four statements execute because withdrawal <= balance is True. If we change the withdrawal to 2000:

python
# bank_withdrawal_insufficient.py
balance = 1500
withdrawal = 2000
 
if withdrawal <= balance:
    balance = balance - withdrawal
    print(f"Withdrawal successful!")
    print(f"Your new balance is: ${balance}")
    print("Thank you for your transaction.")
 
print("Transaction complete.")  # Always executes

Output:

Transaction complete.

Now none of the indented statements execute because the condition is False. The balance remains unchanged at 1500.

8.2) Using if-else for Either-Or Choices

Often you need to choose between two alternatives: execute one block of code if a condition is true, and a different block if it's false. The if-else statement handles this either-or decision-making.

8.2.1) The Structure of if-else

Here's the syntax:

python
if condition:
    # Code to execute if condition is True
    statement1
    statement2
else:
    # Code to execute if condition is False
    statement3
    statement4

The else clause provides an alternative path. Exactly one of the two blocks will execute—never both, never neither.

Yes

No

Start

Is condition True?

Execute if block

Execute else block

Continue with rest of program

End

Let's see a practical example:

python
# age_verification.py
age = int(input("Enter your age: "))
 
if age >= 18:
    print("You are an adult.")
    print("You can vote in elections.")
else:
    print("You are a minor.")
    print("You cannot vote yet.")
 
print("Thank you for providing your age.")

If you enter 25:

You are an adult.
You can vote in elections.
Thank you for providing your age.

If you enter 15:

You are a minor.
You cannot vote yet.
Thank you for providing your age.

Notice that exactly one of the two blocks executes, depending on the condition. The final print() statement always executes because it's outside both blocks.

8.2.2) Making Binary Decisions

if-else is perfect for binary decisions where there are exactly two possible outcomes:

python
# even_odd_checker.py
number = int(input("Enter a number: "))
 
if number % 2 == 0:
    print(f"{number} is even.")
else:
    print(f"{number} is odd.")
python
# password_verification.py
stored_password = "python123"
entered_password = input("Enter password: ")
 
if entered_password == stored_password:
    print("Access granted.")
    print("Welcome to the system!")
else:
    print("Access denied.")
    print("Incorrect password.")

8.3) Multiple Choices with if-elif-else

Real-world decisions often involve more than two options. Should we charge standard shipping, express shipping, or overnight shipping? Is a grade an A, B, C, D, or F? The if-elif-else chain handles multiple mutually exclusive alternatives.

8.3.1) The Structure of if-elif-else

Here's the syntax:

python
if condition1:
    # Execute if condition1 is True
    block1
elif condition2:
    # Execute if condition1 is False and condition2 is True
    block2
elif condition3:
    # Execute if condition1 and condition2 are False, and condition3 is True
    block3
else:
    # Execute if all conditions are False
    block4

Key points about if-elif-else chains:

  1. elif is short for "else if": It provides additional conditions to check
  2. Order matters: Python checks conditions from top to bottom
  3. First match wins: Once a condition is True, that block executes and the rest are skipped
  4. Exactly one block executes: At most one block in the chain will run
  5. else is optional: It catches all cases not handled by previous conditions

Yes

No

Yes

No

Yes

No

Start

Is condition1 True?

Execute block1

Is condition2 True?

Execute block2

Is condition3 True?

Execute block3

Execute else block

Continue with rest of program

End

Let's see a practical example:

python
# grade_calculator.py
score = int(input("Enter your exam score (0-100): "))
 
if score >= 90:
    grade = "A"
    print("Excellent work!")
elif score >= 80:
    grade = "B"
    print("Good job!")
elif score >= 70:
    grade = "C"
    print("Satisfactory.")
elif score >= 60:
    grade = "D"
    print("You passed, but consider reviewing the material.")
else:
    grade = "F"
    print("Unfortunately, you did not pass.")
 
print(f"Your grade is: {grade}")

If you enter 85:

Good job!
Your grade is: B

Let's trace through what happens:

  1. Check score >= 90: False (85 is not >= 90), so skip this block
  2. Check score >= 80: True (85 >= 80), so execute this block
  3. Skip all remaining elif and else blocks because we found a match

If you enter 55:

Unfortunately, you did not pass.
Your grade is: F

All conditions are False, so the else block executes.

8.3.2) Why Order Matters in elif Chains

The order of conditions is crucial because Python stops checking as soon as it finds a True condition. Consider this incorrect grading system:

python
# INCORRECT ORDER - Don't do this!
score = 85
 
if score >= 60:  # This will match first!
    grade = "D"
elif score >= 70:
    grade = "C"
elif score >= 80:
    grade = "B"
elif score >= 90:
    grade = "A"
else:
    grade = "F"
 
print(f"Your grade is: {grade}")  # Output: Your grade is: D

This gives the wrong result! The score of 85 should be a B, but it gets a D because score >= 60 is checked first and is True. Python never reaches the score >= 80 condition.

Always order conditions from most specific to least specific:

python
# CORRECT ORDER
score = 85
 
if score >= 90:  # Most specific
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 70:
    grade = "C"
elif score >= 60:
    grade = "D"
else:  # Least specific
    grade = "F"
 
print(f"Your grade is: {grade}")  # Output: Your grade is: B

8.3.3) Using elif Without else

The else clause is optional. Sometimes you only want to handle specific cases and do nothing for others:

python
# weekend_checker.py
day = input("Enter a day of the week: ").lower()
 
if day == "saturday" or day == "sunday":
    print("It's the weekend! Time to relax.")
elif day == "friday":
    print("It's Friday! The weekend is almost here.")
elif day in ["monday", "tuesday", "wednesday", "thursday"]:
    print("It's a weekday. Time to work or study.")
# No else clause - if none of these match, nothing happens
 
print("Have a great day!")

If you enter "holiday":

Have a great day!

No condition matched, and there's no else clause, so only the final print() executes.

8.4) Nested if Statements

Sometimes you need to make a decision within a decision. Nested if statements place one conditional inside another, allowing you to check additional conditions only after an initial condition is met.

8.4.1) Understanding Nested Conditionals

Nested if statements are powerful because they let you avoid checking conditions that don't make sense yet. For example, there's no point asking for a password if the user doesn't have an account. Nesting lets you structure your logic to match real-world decision-making processes where some questions only make sense after others are answered.

A nested if statement is simply an if statement (or if-elif-else chain) inside another if block:

python
if outer_condition:
    # This code executes if outer_condition is True
    if inner_condition:
        # This code executes if BOTH conditions are True
        inner_block
    else:
        # This executes if outer_condition is True but inner_condition is False
        inner_else_block
else:
    # This executes if outer_condition is False
    outer_else_block

The inner if statement only gets evaluated if the outer condition is True. This creates a hierarchy of decisions.

No

Yes

Yes

No

Start

Outer condition True?

Execute outer else block

Inner condition True?

Execute inner if block

Execute inner else block

Continue

End

Here's a simple example:

python
# account_login.py
has_account = input("Do you have an account? (yes/no): ").lower() == "yes"
 
if has_account:
    print("Welcome back!")
    password = input("Enter your password: ")
    
    if password == "secret123":
        print("Login successful!")
        print("Access granted to your dashboard.")
    else:
        print("Incorrect password.")
        print("Access denied.")
else:
    print("Please create an account first.")
    print("Visit our registration page.")

If you answer "yes" and enter the correct password:

Welcome back!
Login successful!
Access granted to your dashboard.

If you answer "yes" but enter the wrong password:

Welcome back!
Incorrect password.
Access denied.

If you answer "no":

Please create an account first.
Visit our registration page.

Notice how the password check only happens if the user has an account. This is the key benefit of nesting—you can avoid unnecessary checks.

8.4.2) When to Use Nested if Statements

Nested if statements are useful when:

  1. Decisions depend on previous decisions: You need to check something only after another condition is met
  2. Creating decision trees: Each level narrows down the possibilities
  3. Validating prerequisites: Check basic requirements before checking detailed requirements
  4. Avoiding unnecessary checks: Skip expensive operations when earlier conditions fail

Example: Eligibility for a loan

python
# loan_eligibility.py
age = int(input("Enter your age: "))
 
if age >= 18:
    print("Age requirement met.")
    income = float(input("Enter your annual income: $"))
    
    if income >= 30000:
        print("Income requirement met.")
        credit_score = int(input("Enter your credit score: "))
        
        if credit_score >= 650:
            print("Congratulations! You are eligible for a loan.")
            print("Please proceed to the application form.")
        else:
            print("Sorry, your credit score is too low.")
            print("Minimum required: 650")
    else:
        print("Sorry, your income is too low.")
        print("Minimum required: $30,000")
else:
    print("Sorry, you must be 18 or older to apply.")

This creates a decision tree where each level depends on the previous one. If age is under 18, we never ask about income or credit score.

8.4.3) Avoiding Excessive Nesting

While nesting is powerful, too many levels make code hard to read and understand. Consider this deeply nested example:

python
# Too deeply nested - hard to follow
if condition1:
    if condition2:
        if condition3:
            if condition4:
                if condition5:
                    print("All conditions met!")

This is difficult to read and maintain. Here are strategies to reduce nesting:

Strategy 1: Combine conditions when appropriate

We'll learn about the and operator in detail in Chapter 9, but for now, just know it lets you check multiple conditions at once:

python
# Better: Use 'and' to combine conditions (Chapter 9 will explain this fully)
# We'll learn about 'and' in Chapter 9, but for now, just know it checks
# that all conditions are true
if condition1 and condition2 and condition3 and condition4 and condition5:
    print("All conditions met!")

Strategy 2: Use early returns (when working with functions, which we'll learn in Chapter 19):

python
# In a function, we can return early
def check_eligibility(age, income, credit_score):
    if age < 18:
        return "Too young"
    if income < 30000:
        return "Income too low"
    if credit_score < 650:
        return "Credit score too low"
    return "Eligible"

Strategy 3: Flatten with elif when appropriate:

python
# Instead of nested ifs checking ranges
if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 70:
    grade = "C"
# ... and so on

8.5) Common if Statement Pitfalls (Indentation, Colons, and Logic)

Even experienced programmers make mistakes with if statements. This section covers the most common errors beginners encounter and how to avoid them.

8.5.1) Indentation Errors

Python uses indentation to determine which statements belong to which block. Incorrect indentation is one of the most common sources of errors.

Problem 1: Missing indentation

python
# INCORRECT - IndentationError
age = 20
 
if age >= 18:
print("You are an adult.")  # Not indented!

This produces:

  File "example.py", line 4
    print("You are an adult.")
    ^
IndentationError: expected an indented block

Solution: Always indent the block under an if statement:

python
# CORRECT
age = 20
 
if age >= 18:
    print("You are an adult.")  # Properly indented

Problem 2: Inconsistent indentation

python
# INCORRECT - Mixing spaces and tabs, or inconsistent spaces
if temperature > 30:
    print("It's hot!")
      print("Stay hydrated!")  # Extra spaces - inconsistent indentation

Solution: Use consistent indentation (4 spaces is the Python standard):

python
# CORRECT
if temperature > 30:
    print("It's hot!")
    print("Stay hydrated!")  # Same indentation level

Problem 3: Incorrect nesting indentation

python
# INCORRECT - Wrong indentation level
if has_account:
    print("Welcome!")
    if password == "correct":
    print("Login successful!")  # Should be indented more

Solution: Each nested level needs additional indentation:

python
# CORRECT
if has_account:
    print("Welcome!")
    if password == "correct":
        print("Login successful!")  # Properly indented for nested block

8.5.2) Missing Colons

The colon (:) at the end of if, elif, and else lines is required. Forgetting it is a very common mistake:

python
# INCORRECT - SyntaxError: missing colon
if age >= 18
    print("Adult")

This produces:

  File "example.py", line 2
    if age >= 18
                ^
SyntaxError: invalid syntax

Solution: Always include the colon:

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

The same applies to elif and else:

python
# CORRECT - All colons present
if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
else:
    grade = "F"

8.5.3) Incorrect Comparison Operators

Problem 1: Using assignment (=) instead of comparison (==)

python
# INCORRECT - This assigns 18 to age, doesn't compare!
age = 20
 
if age = 18:  # SyntaxError
    print("You are 18")

Solution: Use == for comparison:

python
# CORRECT
age = 20
 
if age == 18:
    print("You are 18")

8.5.4) Unreachable Code Due to Logic Errors

Problem: Conditions that can never be True

python
# INCORRECT - The elif can never execute
score = 85
 
if score >= 60:
    print("You passed!")
elif score >= 80:  # This will never execute!
    print("You got a B!")

If score is 85, the first condition (score >= 60) is True, so the elif never gets checked. The order is wrong.

Solution: Order conditions from most specific to least specific:

python
# CORRECT
score = 85
 
if score >= 80:
    print("You got a B!")
elif score >= 60:
    print("You passed!")

8.5.5) Empty if Blocks

You cannot have an empty if block in Python:

python
# INCORRECT - SyntaxError
if temperature > 30:
    # I'll add code here later
 
print("Done")

This produces:

  File "example.py", line 3
    print("Done")
    ^
IndentationError: expected an indented block

Solution: Use the pass statement as a placeholder (covered in the next section):

python
# CORRECT - Using pass as a placeholder
if temperature > 30:
    pass  # TODO: Add code here later
 
print("Done")

8.6) Using pass as a Placeholder in Blocks

Sometimes when writing code, you know you need an if statement but haven't decided what code should go in it yet. Python doesn't allow empty code blocks, so you need a way to create a valid but "do nothing" block. That's where the pass statement comes in.

8.6.1) What is pass?

The pass statement is a null operation—when Python executes it, nothing happens. It's a placeholder that allows you to write syntactically correct code even when you don't have the implementation ready yet.

python
if condition:
    pass  # Do nothing for now

Think of pass as a way to tell Python: "I know I need code here, but I'll fill it in later." It's particularly useful during development when you're sketching out the structure of your program.

8.6.2) Why pass is Necessary

Python requires at least one statement in every code block. An empty block causes a syntax error:

python
# INCORRECT - This causes an error
if age >= 18:
    # TODO: Add adult logic here
 
print("Done")

Error:

  File "example.py", line 3
    print("Done")
    ^
IndentationError: expected an indented block

Using pass makes the code syntactically valid:

python
# CORRECT - Using pass as a placeholder
if age >= 18:
    pass  # TODO: Add adult logic here
 
print("Done")

8.6.3) Common Uses of pass

Use 1: Placeholder during development

When you're outlining your program's structure but haven't implemented everything yet:

python
# user_system.py
user_type = input("Enter user type (admin/user/guest): ").lower()
 
if user_type == "admin":
    pass  # TODO: Implement admin features
elif user_type == "user":
    pass  # TODO: Implement user features
elif user_type == "guest":
    print("Welcome, guest! Limited access granted.")
else:
    print("Invalid user type.")

This lets you run the program and test the parts you have implemented while leaving placeholders for future work.

Use 2: Intentionally doing nothing in one branch

Sometimes you genuinely want to do nothing in certain cases but need to handle other cases:

python
# positive_numbers.py
# Only process positive numbers
number = int(input("Enter a number: "))
 
if number > 0:
    result = number * 2
    print(f"Double of {number} is {result}")
elif number == 0:
    pass  # Zero is valid but requires no action
else:
    print("Negative numbers are not allowed.")

8.6.4) pass in Other Contexts

While we've focused on pass in if statements, you'll encounter it in other contexts as you learn more Python:

  • Functions (Chapter 20): Placeholder for function bodies
  • Classes (Chapter 31): Placeholder for class definitions
  • Loops (Chapters 11-12): Placeholder for loop bodies
  • Exception handlers (Chapter 29): Intentionally ignoring errors

For now, remember that pass is your tool for creating valid but empty code blocks when you need them.


Bringing It All Together

In this chapter, you've learned how to make your programs intelligent and responsive by using conditional statements. Let's review the key concepts:

Simple if statements execute code only when a condition is true:

python
if temperature > 30:
    print("It's hot outside!")

if-else statements choose between two alternatives:

python
if age >= 18:
    print("Adult")
else:
    print("Minor")

if-elif-else chains handle multiple mutually exclusive options:

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

Nested if statements make decisions within decisions:

python
if has_account:
    if password_correct:
        print("Welcome!")
    else:
        print("Wrong password")
else:
    print("Create an account")

Common pitfalls to avoid:

  • Missing colons after if, elif, and else
  • Incorrect or inconsistent indentation
  • Using = instead of == for comparison
  • Wrong order in elif chains
  • Empty blocks without pass

The pass statement serves as a placeholder for empty blocks during development.

You now have the tools to write programs that make intelligent decisions based on conditions. In the next chapter, we'll learn about boolean logic operators (and, or, not) that let you combine multiple conditions into more sophisticated decision-making logic. This will make your if statements even more powerful and expressive.

© 2025. Primesoft Co., Ltd.
support@primesoft.ai