12 Making Decisions - Controlling Your Program’s Flow
12.1 Chapter Outline
- Understanding conditional execution and its importance
- The
if
statement structure and syntax - Building effective boolean expressions as conditions
- Creating alternative paths with
else
branches - Handling multiple conditions with
elif
- Combining conditions with logical operators
- Designing clean, readable decision structures
- Implementing conditional logic in your chatbot
12.2 Learning Objectives
By the end of this chapter, you will be able to: - Create programs that make intelligent decisions based on conditions - Write if
, elif
, and else
statements with proper syntax and structure - Develop complex boolean expressions to evaluate conditions precisely - Design effective branching logic for different scenarios - Structure multiple decision paths for diverse user interactions - Combine conditions using logical operators for sophisticated tests - Apply conditional logic to make your chatbot respond intelligently - Debug common issues in conditional statements
12.3 1. Introduction: The Power of Choice in Programming
So far, our programs have been linear—they execute from top to bottom, following the same path each time. While useful, these programs can’t adapt to different situations or respond differently based on varying inputs. True programming power comes when your code can make decisions.
Decision-making transforms your programs from fixed sequences into dynamic, responsive systems. It’s the difference between:
- A calculator that only adds numbers vs. one that chooses the right operation based on user input
- A chatbot that says the same thing every time vs. one that responds differently to different messages
- A game that always follows the same pattern vs. one that adapts to player actions
Key Concept: Conditional statements are the branching points in your code—places where your program asks a question and chooses a path based on the answer. Without conditionals, programs remain static and inflexible.
In everyday life, we constantly make decisions based on conditions: “If it’s raining, I’ll take an umbrella,” or “If the store is open, I’ll buy groceries; otherwise, I’ll order delivery.” Conditional statements in programming work the same way, letting your programs adapt to circumstances just as you do.
12.4 2. The if
Statement: Your First Decision Point
The if
statement is the fundamental building block of decision-making in Python. It evaluates a condition and executes a block of code only when that condition is True
:
if condition:
# This code runs only if the condition is True
statement1
statement2# and so on...
# This code always runs, regardless of the condition
outside_statement
Let’s break down the key components:
if
: The keyword that signals a decision pointcondition
: An expression that evaluates to eitherTrue
orFalse
:
: The colon marks the end of the condition and the start of the conditional block- Indented block: All indented statements form the “body” of the
if
statement and execute only when the condition isTrue
Here’s a concrete example:
= 32
temperature
if temperature > 30:
print("It's hot today!")
print("Remember to stay hydrated.")
print("Enjoy your day!") # This always executes
When temperature
is 32, both statements in the if
block will run because the condition temperature > 30
evaluates to True
. However, if temperature
were 25, those statements would be skipped, and only “Enjoy your day!” would be displayed.
12.4.1 Indentation Matters
Unlike many programming languages that use braces {}
or keywords like begin
/end
to define blocks, Python uses indentation. This makes the code cleaner but requires careful attention to spacing:
if temperature > 30:
print("It's hot today!") # Indented (part of the if block)
print("Enjoy your day!") # Not indented (outside the if block)
The standard indentation is 4 spaces, though the exact number is less important than consistency. Whatever indentation you choose, stick with it throughout your code.
12.5 3. Building Effective Conditions
A condition is any expression that evaluates to either True
or False
, known as a “boolean expression.” You can create conditions using:
12.5.1 Comparison Operators
These operators compare values and return a boolean result:
= 25
age
> 18 # Greater than: True if age is greater than 18
age < 65 # Less than: True if age is less than 65
age >= 21 # Greater than or equal to: True if age is at least 21
age <= 30 # Less than or equal to: True if age is at most 30
age == 25 # Equal to: True if age is exactly 25
age != 30 # Not equal to: True if age is not 30 age
12.5.2 Boolean Variables
Variables that directly store True
or False
values:
= True
is_student = False
has_membership
if is_student:
print("Student discount applied")
if not has_membership:
print("Consider upgrading to a membership")
12.5.3 Membership Tests
Check if a value exists within a sequence:
= ["apple", "banana", "cherry"]
fruits = "banana"
choice
if choice in fruits:
print(f"We have {choice}!")
if "orange" not in fruits:
print("Sorry, we don't have oranges")
12.5.4 String Operations
Check properties or contents of strings:
= "Alice Johnson"
name
if name.startswith("A"):
print("Name starts with A")
if "son" in name:
print("Name contains 'son'")
if name.isalpha(): # Would be False because of the space
print("Name contains only letters")
12.5.5 Function Results
Functions that return boolean values:
= "user@example.com"
email
def is_valid_email(email):
return "@" in email and "." in email
if is_valid_email(email):
print("Email format looks valid")
12.5.6 Boolean Clarity
For complex conditions, storing the result in a descriptively named boolean variable improves readability:
= 25
age = 45000
income = 720
credit_score
# Hard to read directly in the if statement
if age >= 21 and income >= 40000 and credit_score >= 700:
print("Loan approved")
# Clearer with descriptive boolean variables
= age >= 21
meets_age_requirement = income >= 40000
meets_income_requirement = credit_score >= 700
meets_credit_requirement
if meets_age_requirement and meets_income_requirement and meets_credit_requirement:
print("Loan approved")
This approach makes your code self-documenting—the boolean variable names explain what’s being checked.
12.6 4. Adding Alternatives with else
The else
clause provides an alternative path when the condition is False
:
= 25
temperature
if temperature > 30:
print("It's hot today!")
print("Remember to stay hydrated.")
else:
print("It's not very hot today.")
print("Normal precautions are sufficient.")
print("Enjoy your day!") # This always executes
When the condition is False
(as it is when temperature
is 25), the else
block executes instead of the if
block. This creates a simple “either-or” decision structure.
The else
clause is optional. Use it when you need to choose between exactly two alternatives; omit it when you only need to execute code conditionally without an alternative.
12.7 5. Multiple Choices with elif
Real-world decisions often involve more than two options. The elif
(short for “else if”) statement lets you check multiple conditions in sequence:
= 22
temperature
if temperature > 30:
print("It's a hot day!")
print("Remember to stay hydrated.")
elif temperature > 20:
print("It's a pleasant day!")
print("Enjoy the nice weather.")
elif temperature > 10:
print("It's a bit cool today.")
print("Consider wearing a light jacket.")
else:
print("It's cold today!")
print("Don't forget your coat.")
print("Have a great day!") # This always executes
Python evaluates each condition in order: 1. First, it checks if temperature > 30
(False when temperature is 22) 2. Then, it checks if temperature > 20
(True when temperature is 22) 3. Since the second condition is True, it executes that block and skips the rest
Only one block will execute, even if multiple conditions could be true. The first true condition “wins,” and the rest are skipped.
12.7.1 The Importance of Order
The order of your elif
statements matters. Consider this example:
= 85
score
# Correct order (most specific to least specific)
if score >= 90:
= "A"
grade elif score >= 80:
= "B"
grade elif score >= 70:
= "C"
grade elif score >= 60:
= "D"
grade else:
= "F" grade
If we reversed the order:
# Incorrect order (least specific to most specific)
if score >= 60:
= "D" # This would always trigger first for any passing score!
grade elif score >= 70:
= "C" # These would never be reached for passing scores
grade elif score >= 80:
= "B"
grade elif score >= 90:
= "A"
grade else:
= "F" grade
With a score of 85, the first example correctly assigns grade “B”, but the second incorrectly assigns “D” because the first condition is already true.
Best Practice: When conditions overlap, arrange them from most specific/restrictive to most general.
12.8 6. Combining Conditions with Logical Operators
To create more sophisticated conditions, you can combine simpler ones using logical operators:
12.8.1 The and
Operator
True only if both conditions are true:
= 25
age = 50000
income
if age >= 21 and income >= 40000:
print("Eligible for premium credit card")
12.8.2 The or
Operator
True if at least one condition is true:
= True
is_holiday = False
is_weekend
if is_holiday or is_weekend:
print("The office is closed")
12.8.3 The not
Operator
Inverts a boolean value:
= True
is_working_day
if not is_working_day:
print("You can sleep in today")
else:
print("Time to go to work")
12.8.4 Complex Combinations
You can create complex conditions by combining these operators:
= 65
age = 30000
income = False
is_student = True
has_disability
# Eligible if:
# - Senior (65+) or student or has disability
# - AND income under 35000
if (age >= 65 or is_student or has_disability) and income < 35000:
print("Eligible for financial assistance")
Use parentheses to make the precedence clear, even if not strictly necessary for the logic.
12.9 7. Nested Conditionals: Decisions Within Decisions
Sometimes, you need to make a decision based on the outcome of another decision. This creates a nested conditional structure:
= True
has_ticket = False
has_id
if has_ticket:
# This entire block only runs if has_ticket is True
print("Ticket verified.")
if has_id:
print("ID verified. Welcome to the event!")
else:
print("Sorry, you need ID to enter. Please return with ID.")
else:
print("You need a ticket to enter. Please purchase one first.")
While nesting can express complex logic, deep nesting (more than 2-3 levels) can make code hard to follow. Often, you can flatten nested conditions using logical operators:
# Instead of nesting:
if has_ticket:
if has_id:
print("Welcome to the event!")
else:
print("ID required")
else:
print("Ticket required")
# You can use logical operators:
if has_ticket and has_id:
print("Welcome to the event!")
elif has_ticket: # At this point, we know has_id is False
print("ID required")
else:
print("Ticket required")
The flattened version is often easier to read and maintain.
12.10 8. Common Patterns in Decision Making
Here are some common decision-making patterns you’ll use frequently:
12.10.1 Input Validation
= input("Enter your age: ")
user_age
if user_age.isdigit():
= int(user_age)
age if age >= 18:
print("Access granted")
else:
print("Sorry, you must be 18 or older")
else:
print("Please enter a valid number")
12.10.2 Mutually Exclusive Categories
When options are mutually exclusive (only one can be true):
= "red"
color
if color == "red":
print("Stop")
elif color == "yellow":
print("Caution")
elif color == "green":
print("Go")
else:
print("Unknown signal")
12.10.3 Independent Checks
When you need to perform multiple independent checks:
# Each check is independent - multiple messages can print
= 35
temperature = 80
humidity = "Poor"
air_quality
if temperature > 30:
print("Heat advisory in effect")
if humidity > 70:
print("High humidity warning")
if air_quality == "Poor":
print("Air quality alert")
12.10.4 Early Returns and Guards
In functions, using conditionals to “guard” against invalid cases:
def divide(a, b):
# Guard against division by zero
if b == 0:
print("Error: Cannot divide by zero")
return None # Early return
# Only reached if b is not zero
return a / b
12.10.5 State Machines
Using conditionals to model different states:
= "pending"
status = 5
days_active
if status == "pending":
print("Order is awaiting processing")
elif status == "processing":
print("Order is being prepared")
elif status == "shipped":
if days_active < 3:
print("Order recently shipped")
else:
print("Order in transit")
elif status == "delivered":
print("Order has been delivered")
else:
print("Unknown order status")
12.11 9. Project Corner: Making Your Chatbot Intelligent
Now let’s apply what we’ve learned to enhance our chatbot with conditional logic, giving it the ability to respond intelligently to different inputs.
12.11.1 Basic Decision Tree Chatbot
Let’s start with a simple decision tree based on keywords:
def get_response(user_input, user_name):
"""
Generate a response based on user input.
Args:
user_input (str): The user's message
user_name (str): The user's name
Returns:
str: The chatbot's response
"""
# Convert to lowercase for easier matching
= user_input.lower()
user_input
# Check for special commands
if user_input == "help":
return f"""
Hi {user_name}! I can respond to various topics:
- Greetings (hello, hi)
- Questions about myself
- Questions about Python
- Expressions of mood (happy, sad)
- Weather inquiries
- Farewells (bye, goodbye)
Just type naturally and I'll try to understand!
"""
# Check for greetings
if "hello" in user_input or "hi" in user_input or user_input == "hey":
return f"Hello {user_name}! How can I help you today?"
# Check for questions about the bot
elif "your name" in user_input:
return "My name is PyBot. I'm a chatbot built as part of your Python learning journey!"
elif "who are you" in user_input or "what are you" in user_input:
return "I'm PyBot, a simple chatbot designed to demonstrate Python conditional statements."
# Check for Python questions
elif "python" in user_input and "?" in user_input:
return "Python is a versatile programming language known for its readability and ease of use. What specific aspect would you like to know about?"
elif "function" in user_input and "python" in user_input:
return "Functions in Python are defined using the 'def' keyword. They help organize and reuse code."
elif "conditional" in user_input or "if statement" in user_input:
return "Conditional statements in Python, like 'if', 'elif', and 'else', let your programs make decisions based on conditions."
# Check for mood expressions
elif "happy" in user_input or "glad" in user_input or "good" in user_input:
return f"I'm glad you're feeling positive, {user_name}! What's made your day good?"
elif "sad" in user_input or "bad" in user_input or "terrible" in user_input:
return f"I'm sorry to hear that, {user_name}. Remember that tough times don't last forever."
# Check for weather inquiries
elif "weather" in user_input:
if "hot" in user_input:
return "In hot weather, staying hydrated is important. Drink plenty of water!"
elif "cold" in user_input or "cool" in user_input:
return "Cold weather can be invigorating! A hot beverage might be nice."
elif "rain" in user_input:
return "Rainy days are perfect for indoor activities. Maybe some Python practice?"
else:
return "Weather affects our daily lives significantly. How's the weather affecting your plans?"
# Check for farewells
elif "bye" in user_input or "goodbye" in user_input:
return f"Goodbye, {user_name}! It was nice chatting with you. Come back soon!"
# Default response for unrecognized input
else:
return f"That's interesting, {user_name}. Tell me more, or type 'help' to see what I can discuss."
def run_chatbot():
"""Run the main chatbot interaction loop."""
= "PyBot"
bot_name
print(f"\nHello! I'm {bot_name}, your Python learning assistant.")
= input("What's your name? ").strip()
user_name print(f"\n{bot_name}> Nice to meet you, {user_name}! Type 'help' for options or 'bye' to exit.")
while True:
= input(f"\n{user_name}> ").strip()
user_input
# Exit condition
if user_input.lower() == "bye":
print(f"\n{bot_name}> Goodbye, {user_name}! Have a great day!")
break
# Get and display response
= get_response(user_input, user_name)
response print(f"\n{bot_name}> {response}")
# Run the chatbot if this file is executed directly
if __name__ == "__main__":
run_chatbot()
This basic chatbot demonstrates several conditional concepts: - Using if
/elif
/else
for different categories of input - Nested conditions for subcategories (like weather types) - Keyword detection with the in
operator - Combining conditions with or
for similar triggers
12.11.2 Advanced Context-Aware Chatbot
Let’s enhance our chatbot to remember context and respond more intelligently:
def context_aware_chatbot():
"""A more sophisticated chatbot that maintains conversation context."""
= "PyBot"
bot_name
# Initialize conversation state
= {
context "user_name": "",
"topics_discussed": set(),
"question_count": 0,
"mood": "neutral", # bot's mood: can be "happy", "neutral", or "tired"
"last_topic": None
}
# Helper function to update context
def update_context(user_input):
# Track topics
if "python" in user_input.lower():
"topics_discussed"].add("python")
context[if "weather" in user_input.lower():
"topics_discussed"].add("weather")
context[if "music" in user_input.lower():
"topics_discussed"].add("music")
context[
# Track questions
if "?" in user_input:
"question_count"] += 1
context[
# Update mood (bot gets "tired" after many questions)
if context["question_count"] > 5:
"mood"] = "tired"
context[
# Track last topic mentioned
for topic in ["python", "weather", "music", "movies", "books"]:
if topic in user_input.lower():
"last_topic"] = topic
context[break
# Main response function
def get_contextual_response(user_input):
= user_input.lower()
user_input
update_context(user_input)
# Special case for greeting - depends on bot's mood
if "hello" in user_input or "hi" in user_input:
if context["mood"] == "happy":
return f"Hello {context['user_name']}! It's wonderful to see you! How can I help you today?"
elif context["mood"] == "tired":
return f"Hi {context['user_name']}... You've asked quite a few questions. I'll try to keep up!"
else:
return f"Hello {context['user_name']}! How can I help you today?"
# Check for questions about previous topics
if "tell me more" in user_input and context["last_topic"]:
= context["last_topic"]
topic if topic == "python":
return "Python is a versatile language used for web development, data analysis, AI, and more. What specific aspect interests you?"
elif topic == "weather":
return "Weather is the state of the atmosphere, including temperature, humidity, wind, etc. Any specific weather phenomenon you're curious about?"
elif topic == "music":
return "Music comes in countless genres from classical to electronic. Do you have a favorite style?"
else:
return f"You wanted to know more about {topic}? What specific aspect interests you?"
# Check for topic switching
= context["topics_discussed"].copy()
prev_topics # This adds any new topics
update_context(user_input) = context["topics_discussed"] - prev_topics
new_topics
if new_topics and len(prev_topics) > 0:
= list(new_topics)[0]
new_topic return f"I see we're now talking about {new_topic}. That's an interesting switch from our previous topics!"
# Check for Python questions with contextual awareness
if "python" in user_input and context["topics_discussed"]:
if "weather" in context["topics_discussed"]:
return "Python can be used for weather data analysis and forecasting! Libraries like MetPy are specifically designed for meteorological calculations."
elif "music" in context["topics_discussed"]:
return "Python has libraries like librosa for music analysis and pygame for playing sounds. You can even create music with Python!"
# Question counter responses
if "?" in user_input:
if context["question_count"] == 1:
return "That's a good first question! I'm here to help with more."
elif context["question_count"] == 5:
"mood"] = "tired"
context[return "You ask a lot of questions! That's good for learning, but I'm getting a bit tired."
elif context["question_count"] > 8:
return "Wow, you're very curious today! So many questions!"
# If no contextual response matched, fall back to basic responses
if "python" in user_input:
return "Python is a powerful programming language. Is there something specific about Python you'd like to know?"
elif "weather" in user_input:
return "Weather is always an interesting topic. Are you experiencing good weather today?"
elif "bye" in user_input or "goodbye" in user_input:
= len(context["topics_discussed"])
topics = context["question_count"]
questions return f"Goodbye, {context['user_name']}! We discussed {topics} topics and you asked {questions} questions. Come back soon!"
else:
return "I'm listening. Feel free to ask about Python, share your thoughts, or discuss other topics like weather or music."
# Welcome and get user's name
print(f"\nHello! I'm {bot_name}, a context-aware chatbot.")
"user_name"] = input("What's your name? ").strip()
context["mood"] = "happy" # Start in a happy mood
context[
print(f"\n{bot_name}> Nice to meet you, {context['user_name']}! Let's chat about Python, weather, music, or anything else on your mind. Type 'bye' to end our conversation.")
# Main conversation loop
while True:
= input(f"\n{context['user_name']}> ").strip()
user_input
if user_input.lower() == "bye":
print(f"\n{bot_name}> {get_contextual_response(user_input)}")
break
= get_contextual_response(user_input)
response print(f"\n{bot_name}> {response}")
# Run the context-aware chatbot
# context_aware_chatbot() # Uncomment to run
This advanced chatbot demonstrates: - Maintaining state with a context dictionary - Making decisions based on conversation history - Using nested conditionals for complex logic - Adapting responses based on multiple factors - Tracking and counting specific events (questions)
12.11.3 Implementing a Mood System with State Machine
Here’s a focused example of using conditionals to implement a mood system:
def mood_based_chatbot():
"""A chatbot that changes responses based on its current mood state."""
= "MoodBot"
bot_name
# Initialize state
= "neutral" # Can be "happy", "neutral", "irritated", or "sleepy"
bot_mood = 0
interaction_count = 0
user_mood_mentions
print(f"\nHello! I'm {bot_name}. I have different moods that affect how I respond.")
= input("What's your name? ").strip()
user_name
# Welcome message varies by initial mood
print(f"\n{bot_name}> Nice to meet you, {user_name}! Let's chat. Type 'bye' to exit.")
while True:
# Update mood based on interaction count
if interaction_count > 10:
= "sleepy"
bot_mood elif interaction_count > 5 and user_mood_mentions == 0:
= "irritated"
bot_mood
= input(f"\n{user_name}> ").strip().lower()
user_input += 1
interaction_count
# Check for mood-related keywords
if "happy" in user_input or "good" in user_input or "great" in user_input:
+= 1
user_mood_mentions if bot_mood != "sleepy": # If not too sleepy, become happy
= "happy"
bot_mood
# Exit condition
if user_input == "bye":
# Different farewell based on mood
if bot_mood == "happy":
print(f"\n{bot_name}> Farewell, {user_name}! It was a delight chatting with you!")
elif bot_mood == "neutral":
print(f"\n{bot_name}> Goodbye, {user_name}. Have a nice day.")
elif bot_mood == "irritated":
print(f"\n{bot_name}> Finally, some peace and quiet. Bye.")
elif bot_mood == "sleepy":
print(f"\n{bot_name}> *yawn*... Oh, you're leaving? Bye then... *zzz*")
break
# Generate response based on current mood
if user_input == "how are you":
if bot_mood == "happy":
print(f"\n{bot_name}> I'm feeling fantastic today! Thanks for asking!")
elif bot_mood == "neutral":
print(f"\n{bot_name}> I'm doing alright, thanks.")
elif bot_mood == "irritated":
print(f"\n{bot_name}> How am I? How about asking something interesting for once?")
elif bot_mood == "sleepy":
print(f"\n{bot_name}> *yawn*... Sorry, what was the question? I'm a bit tired...")
elif "help" in user_input:
if bot_mood == "happy":
print(f"\n{bot_name}> I'd be delighted to help! What do you need assistance with?")
elif bot_mood == "neutral":
print(f"\n{bot_name}> Sure, I can help. What do you need?")
elif bot_mood == "irritated":
print(f"\n{bot_name}> *sigh* What do you need help with now?")
elif bot_mood == "sleepy":
print(f"\n{bot_name}> Help? *blinks slowly* I'll... try my best... *yawn*")
elif "mood" in user_input:
if bot_mood == "happy":
print(f"\n{bot_name}> I'm in a wonderful mood! Everything feels great today!")
elif bot_mood == "neutral":
print(f"\n{bot_name}> My mood is neutral at the moment.")
elif bot_mood == "irritated":
print(f"\n{bot_name}> I'm feeling rather irritated. Too many pointless questions, perhaps?")
elif bot_mood == "sleepy":
print(f"\n{bot_name}> So... tired... *yawns* Sorry, what were we talking about?")
# Special case - asking about mood resets irritation
if bot_mood == "irritated":
= "neutral"
bot_mood print(f"\n{bot_name}> Actually, talking about it helps. I feel better now.")
else:
# Default response based on mood
if bot_mood == "happy":
print(f"\n{bot_name}> That's fascinating! Tell me more about that!")
elif bot_mood == "neutral":
print(f"\n{bot_name}> Interesting. What else would you like to discuss?")
elif bot_mood == "irritated":
print(f"\n{bot_name}> Is there a point to this conversation?")
elif bot_mood == "sleepy":
print(f"\n{bot_name}> *struggling to keep eyes open* Mmm... that's... nice...")
# Display current mood (for demonstration purposes)
print(f"[Current mood: {bot_mood}]")
# Run the mood-based chatbot
# mood_based_chatbot() # Uncomment to run
This mood system demonstrates: - Using a state variable (bot_mood
) to control response style - Transitioning between states based on conditions - Different responses for the same input based on state - Conditional state transitions based on user interaction
12.12 10. AI Collaboration Corner: Crafting Effective Conditionals
Let’s explore how AI assistants can help you design better conditional logic in your Python programs.
12.12.1 Before: Vague Prompting
Help me with Python if statements.
AI Response: Python if statements let you execute code conditionally. The basic syntax is:
if condition:
# code to run if condition is True
elif other_condition:
# code to run if other_condition is True
else:
# code to run if all conditions are False
You can use comparison operators like ==
, !=
, >
, <
, >=
, and <=
to create conditions. Logical operators and
, or
, and not
can combine multiple conditions.
This response provides basic information but doesn’t address specific design challenges or best practices.
12.12.2 After: Detailed, Specific Prompting
I'm building a user registration system in Python that needs to validate form
submissions. I need to create conditional logic that:
1. Validates username (3-15 chars, letters/numbers only), password (8+ chars,
must include a number), and email (must have @ and .)
2. Provides specific error messages for each type of validation failure
3. Handles special cases like admin users with different validation rules
4. Has clean, readable code that avoids deeply nested conditionals
Please show me well-structured code with effective conditional logic and explain
the design principles you're using.
AI Response: Here’s a well-structured approach to validation with effective conditional logic:
def validate_registration(username, password, email, is_admin=False):
"""
Validate user registration data and return results.
Args:
username (str): Desired username
password (str): Desired password
email (str): User's email address
is_admin (bool): Whether this is an admin account
Returns:
tuple: (is_valid, error_message)
is_valid (bool): True if all validations pass
error_message (str): Description of the first validation error, or None if valid
"""
# Validate username (3-15 chars, letters/numbers only)
if not 3 <= len(username) <= 15:
return False, "Username must be between 3 and 15 characters"
if not username.isalnum():
return False, "Username must contain only letters and numbers"
# Validate password with different rules for admin/regular users
if is_admin:
# Stricter admin password requirements
if len(password) < 12:
return False, "Admin passwords must be at least 12 characters"
# Check for complexity requirements
= any(c.isupper() for c in password)
has_upper = any(c.islower() for c in password)
has_lower = any(c.isdigit() for c in password)
has_digit = any(not c.isalnum() for c in password)
has_special
if not (has_upper and has_lower and has_digit and has_special):
return False, "Admin passwords must include uppercase, lowercase, digits, and special characters"
else:
# Regular user password requirements
if len(password) < 8:
return False, "Password must be at least 8 characters"
if not any(c.isdigit() for c in password):
return False, "Password must include at least one number"
# Validate email (must have @ and .)
if '@' not in email:
return False, "Email must contain @"
if '.' not in email.split('@')[1]:
return False, "Email must contain a valid domain with a dot"
# If we've reached this point, all validations have passed
return True, None
def register_user(username, password, email, is_admin=False):
"""Process user registration with appropriate feedback."""
# First step: validate the input
= validate_registration(username, password, email, is_admin)
is_valid, error_message
if not is_valid:
# Early return pattern - handle the error case first
print(f"Registration failed: {error_message}")
return False
# If we get here, validation passed - continue with registration
= "admin" if is_admin else "regular"
user_type print(f"Successfully registered {user_type} user '{username}'")
# In a real system, you would save the user to a database here
return True
# Example usage
def test_registration():
# Test valid regular user
"alice123", "pass1234", "alice@example.com")
register_user(
# Test invalid username
"a", "pass1234", "short@example.com")
register_user(
# Test invalid password
"bob123", "password", "bob@example.com")
register_user(
# Test invalid email
"charlie", "pass1234", "not-an-email")
register_user(
# Test valid admin
"adminuser", "Admin@1234567", "admin@company.com", is_admin=True)
register_user(
# Test invalid admin (password not complex enough)
"adminuser2", "simple123", "admin2@company.com", is_admin=True) register_user(
This code demonstrates several principles for effective conditional logic:
- Early returns for validation:
- Each validation check immediately returns when it fails
- This avoids deeply nested conditionals (“arrow code”)
- The error message clearly indicates which specific validation failed
- Separation of concerns:
- Validation logic is separated from registration processing
- The
validate_registration
function has a single responsibility - The main
register_user
function uses the “fail fast” pattern
- Conditional branching strategies:
- Special cases (admin vs. regular user) are handled with an initial branch
- Complex conditions use intermediate boolean variables for readability
- Related conditions are grouped together logically
- Design patterns for validation:
- Return both success status and error message
- Specific, actionable error messages
- Default parameter for optional conditions (
is_admin=False
)
These approaches create conditionals that are easy to read, maintain, and extend. The validation can be expanded with additional rules without making the code more complex, and the error handling provides clear guidance to users.
12.12.3 How to Craft Effective Prompts for Conditional Logic
When working with an AI assistant on conditional logic:
Describe the decision-making scenario in detail (user validation, game logic, data processing, etc.)
Specify all the conditions that need to be evaluated
Ask for specific design patterns that help manage complexity
Mention your concerns about readability, maintainability, or edge cases
Request examples of alternative approaches if you’re considering different designs
For example:
I'm writing a discount calculator for an e-commerce site. The rules are:
- 10% off orders over $100
- 15% off orders over $200
- Additional 5% for loyalty members
- Extra 3% on weekends
- Maximum discount of 25%
I want to avoid deeply nested if statements. Can you show me 2-3 different
approaches to implement this logic with pros and cons of each design?
This specific prompt will yield practical approaches to a real-world conditional logic problem, with a discussion of tradeoffs between different designs.
12.12.4 Using AI to Debug Conditional Logic Issues
Conditional logic can be tricky to get right. Here’s how to use AI effectively when debugging:
My Python code isn't working as expected. I have this function to determine
if a user qualifies for free shipping:
def qualifies_for_free_shipping(cart_total, is_member, item_count):
if cart_total > 50 or is_member and item_count > 1:
return True
else:
return False
It should give free shipping when:
- Cart total exceeds $50, OR
- The user is a member AND has more than 1 item
But members with exactly 1 item are getting free shipping. What's wrong with my logic?
AI Response: I see the issue in your conditional logic. There’s an operator precedence problem. The current code is being interpreted as:
if (cart_total > 50) or (is_member and item_count > 1):
But based on your description, you want:
if (cart_total > 50) or (is_member and item_count > 1):
Wait - those look the same, so that’s not the issue. Let me check again…
Actually, your code logic matches your description correctly. If a user is a member AND has more than 1 item, they get free shipping. Or if cart total > $50, they get free shipping regardless of membership or item count.
The problem must be elsewhere. Let’s double-check with some test cases:
Case 1: cart_total = 40, is_member = True, item_count = 1 - cart_total > 50 is False - is_member is True - item_count > 1 is False - So: False or (True and False) → False or False → False - This user should NOT get free shipping
If members with exactly 1 item are getting free shipping, possible causes include: 1. The is_member
value might not be what you expect (check its type and value) 2. The item_count
might not be what you expect (make sure it’s actually 1, not 2) 3. There might be another part of your code that’s overriding this function’s result
I recommend adding debug statements to verify the values:
def qualifies_for_free_shipping(cart_total, is_member, item_count):
print(f"Debug - cart_total: {cart_total}, is_member: {is_member}, item_count: {item_count}")
= cart_total > 50 or (is_member and item_count > 1)
qualifies print(f"Debug - qualifies: {qualifies}")
return qualifies
This will help you confirm what’s actually happening when the function runs.
12.12.5 Creating Complex Decision Trees with AI Assistance
For more complex conditional structures, AI can help design decision trees:
I need to create a loan approval system with these conditions:
- Credit score must be 650+ for any loan
- For loans under $10,000: require 1+ year employment
- For loans $10,000-$50,000: require 2+ years employment and debt-to-income < 40%
- For loans over $50,000: require 3+ years employment, debt-to-income < 35%,
and either a cosigner OR collateral worth at least 30% of loan value
Can you design a function with clean conditional logic for this system, with
detailed rejection reasons?
This specific prompt will yield a comprehensive solution for a complex decision tree, with clean, maintainable code.
By providing specific context and requirements when asking for help with conditionals, you can get much more useful and practical assistance from AI tools.
12.13 11. Common Conditional Logic Pitfalls to Avoid
As you work with conditional statements, watch for these common issues:
12.13.1 Using Assignment (=) Instead of Equality (==)
# INCORRECT - accidentally assigns value instead of comparing
if age = 18: # This is a syntax error in Python
print("You're 18!")
# CORRECT - compares values
if age == 18:
print("You're 18!")
Python’s syntax prevents this common error, but it’s a frequent mistake in many languages.
12.13.2 Missing the Colon
# INCORRECT - missing colon
if age > 18
print("You are an adult.")
# CORRECT
if age > 18:
print("You are an adult.")
12.13.3 Inconsistent Indentation
# INCORRECT - inconsistent indentation
if temperature > 30:
print("It's hot!")
print("Drink water.") # IndentationError
# CORRECT - consistent indentation
if temperature > 30:
print("It's hot!")
print("Drink water.")
12.13.4 Confusing and
/or
Logic
# INCORRECT - inverted logic
# Meant: "If age is at least 18 AND no more than 65"
if age >= 18 or age <= 65: # Always True for any age!
print("Working age")
# CORRECT
if age >= 18 and age <= 65:
print("Working age")
# ALTERNATIVE (cleaner)
if 18 <= age <= 65:
print("Working age")
12.13.5 Forgetting That else
Belongs to the Closest if
# MISLEADING - the else belongs to the inner if, not the outer one
if temperature > 30:
if humidity > 70:
print("Hot and humid")
else: # This else belongs to the humidity check, not the temperature check!
print("Not hot and humid")
# CLEARER - with proper indentation showing structure
if temperature > 30:
if humidity > 70:
print("Hot and humid")
else: # Clearly belongs to the humidity check
print("Hot but not humid")
else: # Clearly belongs to the temperature check
print("Not hot")
12.13.6 Redundant Conditions
# REDUNDANT - unnecessarily verbose
if is_valid == True:
print("Valid")
if has_permission == False:
print("Access denied")
# CLEANER
if is_valid:
print("Valid")
if not has_permission:
print("Access denied")
12.13.7 “Arrow Code” (Deeply Nested Conditionals)
# PROBLEMATIC - deeply nested "arrow code"
def process_order(order):
if order.is_valid:
if order.is_paid:
if order.has_inventory:
if not order.is_shipped:
# Ship the order
order.ship()return "Shipped"
else:
return "Already shipped"
else:
return "No inventory"
else:
return "Not paid"
else:
return "Invalid order"
# BETTER - early returns
def process_order(order):
if not order.is_valid:
return "Invalid order"
if not order.is_paid:
return "Not paid"
if not order.has_inventory:
return "No inventory"
if order.is_shipped:
return "Already shipped"
# If we get here, all conditions are met
order.ship()return "Shipped"
12.13.8 Forgetting That Multiple elif
Conditions Are Exclusive
# MISLEADING - only one block will execute, even if multiple conditions are true
= 95
score
if score > 60:
print("You passed") # This will print
elif score > 90:
print("You got an A") # This won't print, even though it's true
# CORRECT - separate independent conditions
if score > 60:
print("You passed")
if score > 90:
print("You got an A")
12.14 12. Real-World Conditional Logic Examples
Let’s examine how conditionals are used in professional applications:
12.14.1 Form Validation
def validate_form_submission(form_data):
"""Validate a form submission with multiple fields."""
= {}
errors
# Required fields check
= ["name", "email", "phone", "message"]
required_fields for field in required_fields:
if field not in form_data or not form_data[field].strip():
= f"{field.capitalize()} is required"
errors[field]
# If any required fields are missing, return early
if errors:
return False, errors
# Email validation
= form_data["email"]
email if "@" not in email or "." not in email.split("@")[1]:
"email"] = "Please enter a valid email address"
errors[
# Phone validation (simple check for demonstration)
= form_data["phone"]
phone if not (phone.isdigit() and 10 <= len(phone) <= 15):
"phone"] = "Please enter a valid phone number"
errors[
# Message length validation
= form_data["message"]
message if len(message) < 10:
"message"] = "Message must be at least 10 characters"
errors[elif len(message) > 1000:
"message"] = "Message cannot exceed 1000 characters"
errors[
# Return validation result
if errors:
return False, errors
else:
return True, None
12.14.2 E-commerce Discount Calculation
def calculate_discount(order_total, user, day_of_week):
"""Calculate discount based on multiple conditions."""
# Initialize discount
= 0
discount_percentage
# Base discount based on order total
if order_total >= 200:
= 15
discount_percentage elif order_total >= 100:
= 10
discount_percentage elif order_total >= 50:
= 5
discount_percentage
# Member discount
if user.is_premium_member:
+= 5
discount_percentage
# Weekend discount
if day_of_week in ["Saturday", "Sunday"]:
+= 3
discount_percentage
# Seasonal promotion
if user.last_purchase_days > 30:
# Incentive for customers who haven't purchased recently
+= 2
discount_percentage
# Limit maximum discount
= min(discount_percentage, 25)
discount_percentage
# Calculate final discount amount
= order_total * (discount_percentage / 100)
discount_amount
return {
"original_total": order_total,
"discount_percentage": discount_percentage,
"discount_amount": discount_amount,
"final_total": order_total - discount_amount
}
12.14.3 Game Character Status
def update_character_status(character):
"""Update a game character's status based on their attributes."""
# Reset temporary status effects
= []
character.status_effects
# Health-based status
= character.current_health / character.max_health * 100
health_percentage
if health_percentage <= 10:
"Critical")
character.status_effects.append(*= 0.5
character.movement_speed elif health_percentage <= 30:
"Wounded")
character.status_effects.append(*= 0.8
character.movement_speed
# Environment effects
if character.current_biome == "Desert":
if not character.has_item("Water Flask"):
"Dehydrated")
character.status_effects.append(*= 0.7
character.stamina_regen elif character.current_biome == "Tundra":
if not character.has_item("Warm Clothing"):
"Freezing")
character.status_effects.append(*= 0.8
character.attack_speed
# Special ability conditions
if character.class_type == "Berserker" and health_percentage <= 50:
"Rage")
character.status_effects.append(*= 1.5
character.attack_damage
# Check for conflicting status effects
if "Stunned" in character.status_effects and "Rage" in character.status_effects:
# Rage overcomes stun
"Stunned")
character.status_effects.remove(
# Update character's visual appearance based on status
if character.status_effects:
character.update_visual_indicators()
return character.status_effects
These examples demonstrate how conditionals are used to implement complex business logic, multi-factor decisions, and state-based behaviors in professional applications.
12.15 13. Self-Assessment Quiz
Test your understanding of conditional logic in Python:
- What is the correct syntax for an if statement in Python?
if (condition) {code}
if condition: code
if condition then code
if: condition code
- Which of these expressions will evaluate to
False
?5 > 3 and 10 > 8
5 > 3 or 2 > 4
5 > 3 and 2 > 4
not (5 > 3)
- If you have multiple conditions to check, which approach is most efficient?
- Multiple separate
if
statements - A chain of
if
/elif
/else
statements - Nested
if
statements inside each other - It depends on whether the conditions are related or independent
- Multiple separate
- What happens when multiple
elif
conditions areTrue
?- All the corresponding code blocks execute
- Only the first
True
condition’s code block executes - Only the last
True
condition’s code block executes - Python raises an error
- Which statement about the
else
clause is correct?- Every
if
statement must have anelse
clause - An
else
clause belongs to the most recentif
statement that doesn’t already have anelse
- You can have multiple
else
clauses for a singleif
statement - An
else
clause executes if any condition isFalse
- Every
- What is the “early return” pattern used for?
- Optimizing code execution speed
- Avoiding deeply nested conditional structures
- Creating recursive functions
- Implementing event loops
- Which of these is a best practice for conditional logic?
- Using
==
to compare withNone
(e.g.,if x == None:
) - Creating deeply nested structures for complex decisions
- Using descriptive boolean variables for complex conditions
- Duplicating code in each branch for better performance
- Using
- In the context of a chatbot, what is the advantage of using
elif
chains for response selection?- It ensures all possible responses are given for a single input
- It guarantees that exactly one response is selected for each input
- It is faster than using separate
if
statements - It requires less memory than other conditional structures
Answers: 1. b) if condition: code
- Python uses a colon and indentation 2. c) 5 > 3 and 2 > 4
- Only evaluates to True if both conditions are True 3. d) It depends on whether the conditions are related or independent - Use if
/elif
/else
for related, exclusive conditions; separate if
statements for independent conditions 4. b) Only the first True
condition’s code block executes - Python stops checking after finding the first match 5. b) An else
clause belongs to the most recent if
statement that doesn’t already have an else
- This is an important scoping rule 6. b) Avoiding deeply nested conditional structures - It leads to flatter, more readable code 7. c) Using descriptive boolean variables for complex conditions - This improves readability 8. b) It guarantees that exactly one response is selected for each input - Ensuring the chatbot gives a single, appropriate response
12.16 14. Try It Yourself: Conditional Logic Exercises
Practice your conditional skills with these exercises:
12.16.1 Exercise 1: Temperature Advisor
Create a program that: - Asks for the current temperature and whether it’s raining - Provides clothing recommendations based on the conditions - Handles at least 4 different combinations of temperature ranges and weather - Provides specific advice for extreme conditions - Uses nested conditionals appropriately
12.16.2 Exercise 2: Password Strength Checker
Build a function that: - Takes a password string as input - Checks for minimum length (8+ characters) - Verifies it contains at least one uppercase letter - Confirms it has at least one number - Checks for at least one special character - Returns a strength rating (“Weak”, “Medium”, “Strong”, “Very Strong”) - Provides specific feedback on what’s missing
12.16.3 Exercise 3: Enhanced Chatbot Response System
Extend the chatbot from this chapter to: - Remember the user’s name from the beginning of the conversation - Track whether certain topics have been discussed before - Respond differently to the same question if it’s asked multiple times - Have a “mood” system that changes based on user interactions - Use at least one nested conditional for a complex response
12.16.4 Exercise 4: Choose Your Own Adventure Game
Create a simple text adventure game that: - Presents the user with a scenario and multiple choices - Uses conditionals to branch the story based on choices - Has at least 3 levels of choices (decision tree depth) - Includes some choices that remember previous decisions - Uses both if
/elif
/else
chains and separate if
statements appropriately
12.16.5 Exercise 5: Data Analysis and Reporting
Write a program that: - Takes a list of test scores (you can hard-code them or ask for input) - Calculates the average, minimum, and maximum scores - Assigns letter grades based on score ranges - Generates different reports based on the overall class performance - Uses boolean variables to track different performance indicators - Provides specific feedback for improvement areas
12.17 15. Cross-References
- Previous Chapter: Creating Functions — Build reusable code components
- Next Chapter: Lists — Work with collections of data
- Related Topic: Operators — Create the boolean expressions used in conditions
- Project Connection: Going Loopy — Combines loops and conditionals for powerful control
- Advanced Application: Error Handling — Uses conditionals to manage exceptional cases
12.18 16. Summary
In this chapter, you’ve learned the essential skills for making your programs intelligent and responsive through conditional logic:
- Using the
if
statement to execute code selectively based on conditions - Creating alternative paths with
else
and handling multiple options withelif
- Building complex conditions with comparison and logical operators
- Designing clean, readable decision structures that avoid common pitfalls
- Implementing state tracking and context awareness in your chatbot
- Using conditional patterns like early returns to write maintainable code
For our chatbot project, you’ve added the ability to make intelligent decisions based on user input, creating more natural and engaging conversations. As we progress through the book, we’ll build on this foundation to create increasingly sophisticated interactions.
Decision-making is one of the most fundamental aspects of programming. Nearly every non-trivial program uses conditionals in some form, from simple validations to complex business logic. The skills you’ve learned in this chapter will serve you in virtually every program you write.
In the next chapter, we’ll explore lists—Python’s primary tool for working with collections of data. Combined with conditionals, lists will enable us to manage and process multiple pieces of information, further enhancing our chatbot’s capabilities.