Intermediate Python Programming and Application
Control Flow Logic
Beyond Simple Decisions
You already know how to make your code choose a path with if and else. But real-world problems often require more nuanced logic than a simple fork in the road. Sometimes, you need to check multiple conditions at once.
This is where logical operators come in. Python's and, or, and not allow you to chain together boolean expressions to create sophisticated rules. and is true only if all conditions are true. or is true if at least one condition is true. not simply flips a boolean value from true to false, or vice versa.
# Example: Checking login credentials and permissions
username = "admin"
password_correct = True
has_permission = False
# User can access if they are the admin with the right password,
# OR if they have special permission.
if (username == "admin" and password_correct) or has_permission:
print("Access Granted")
else:
print("Access Denied")
# Output: Access Granted
Python is also flexible about what it considers "true" or "false". This concept is called truth value testing, or "truthiness". In a boolean context, like an if statement, Python considers 0, empty strings (""), empty lists ([]), and None to be false. Almost everything else is considered true. This lets you write concise checks like if my_list: instead of the more verbose if len(my_list) > 0:. When you chain conditions with and or or, Python uses a clever trick called to save time.
Keeping Logic Clean
When one decision depends on another, you might be tempted to nest if statements inside each other. This is perfectly valid, but it can quickly get out of hand. Deeply nested conditions create what developers call spaghetti code—a tangled mess that's hard to read and even harder to debug. A good rule of thumb is to avoid nesting more than two or three levels deep.
One way to reduce simple nesting is with a conditional expression, also known as a ternary operator. It's a compact, one-line version of an if-else statement that's perfect for assigning a value to a variable based on a condition.
# Standard if-else
age = 20
if age >= 18:
status = "Adult"
else:
status = "Minor"
# Using a ternary operator
status = "Adult" if age >= 18 else "Minor"
print(status)
# Output: Adult
A Modern Approach to Matching
For complex scenarios with many possible conditions, even a series of if-elif-else statements can become clumsy. Python 3.10 introduced a more elegant solution: structural pattern matching with the match-case statement. It allows you to check a value against several possible patterns, making it ideal for handling different data structures or states.
def process_command(command):
match command:
case ["load", filename]:
print(f"Loading {filename}...")
case ["save", filename, "--overwrite"]:
print(f"Overwriting {filename}...")
case ["quit"] | ["exit"]:
print("Exiting program.")
case _:
# The underscore is a wildcard, catching any other pattern
print("Unknown command.")
process_command(["load", "data.csv"])
process_command(["quit"])
process_command(["do_something"])
# Output:
# Loading data.csv...
# Exiting program.
# Unknown command.
Notice how match-case can check the structure of a list—its length and even the values inside it. It can also combine cases, like ["quit"] | ["exit"]. This is far more readable and powerful than a long chain of if statements with complex indexing and logical checks.
Let's review these concepts to solidify your understanding.
Now, test your knowledge on designing robust control flow.
What is the output of the following Python code?
age = 25
has_license = False
print(age > 18 and has_license or not has_license)
In Python's concept of "truthiness," which of the following values is considered True in a boolean context?
By mastering these techniques, you can write Python code that is not only functional but also clean, readable, and efficient, no matter how complex the decisions get.