Previous | Tutorial index | Next

Tutorial 5: Combining Conditions with and / or

Learning Objective

Use logical operators (and, or, not) to check multiple conditions inside a single if statement, enabling complex decision-making with minimal code.

1. The Theory (Deep Dive)

What are Logical Operators?

In Tutorials 1–4, we used comparison operators (>, <, ==, etc.) to create simple conditions like age > 18. But real-world decisions are rarely that simple.

Logical operators (and, or, not) allow us to combine multiple boolean expressions into a single, compound condition that evaluates to a single True or False.

The Three Logical Operators

Operator Name What it does True Example False Example
and Logical AND Returns True only if both sides are True. (5 > 3) and (10 > 7)True (5 > 3) and (10 < 7)False
or Logical OR Returns True if at least one side is True. (5 > 3) or (10 < 7)True (5 < 3) or (10 < 7)False
not Logical NOT Reverses the boolean value. not (5 > 3)False not (5 < 3)True

The "Short-Circuit" Behavior (Crucial!)

Python is lazy when evaluating compound conditions—it stops as soon as the final result is determined. This is called short-circuiting.

The not Operator

not simply flips a boolean. It's often used to check for "absence" or "failure".

Truthiness in Logic

Python's logical operators don't just return True or False—they return the actual value of the last evaluated operand!

Beginner note: While this is a powerful feature, for this course, we recommend writing conditions that explicitly return True/False for clarity.

2. Syntax and Precedence

Basic Syntax

if condition1 and condition2: # Runs ONLY if BOTH condition1 AND condition2 are True if condition1 or condition2: # Runs if AT LEAST ONE (condition1 or condition2) is True if not condition1: # Runs if condition1 is False

Operator Precedence (Order of Evaluation)

Just like math has rules (multiplication before addition), Python evaluates logical operators in a specific order:

  1. Comparisons (>, <, ==, etc.) happen first.
  2. not comes next.
  3. and comes after not.
  4. or comes last (lowest priority).

Crucial Rule: If you mix and and or in the same statement, and is evaluated before or.

# Without parentheses (confusing) if age >= 18 and age <= 65 or age == 0: # This is evaluated as: (age >= 18 and age <= 65) or age == 0 # With parentheses (CLEAR and SAFE) if (age >= 18 and age <= 65) or (age == 0): # This is evaluated exactly as intended.

Golden Rule: Always use parentheses () to make your intentions crystal clear. It prevents bugs and makes your code easier to read.

Python's Comparison Chaining (Alternative to and)

Python allows a unique shorthand for checking if a value is within a range:

3. Expanded Code Examples

Example 1: The Classic Login System (Practice Task)

Objective: Grant access only if the username is "admin" AND the password is "secret".

username = input("Enter username: ") password = input("Enter password: ") if username == "admin" and password == "secret": print("Access Granted. Welcome, admin!") else: print("Access Denied. Invalid credentials.")

Example 2: The Weekend & Holiday Checker

day = input("Enter day: ").lower() is_holiday = input("Is it a holiday? (yes/no): ").lower() == "yes" if day == "saturday" or day == "sunday" or is_holiday: print("You get to relax today!") else: print("It's a workday.")

Example 3: Validating Numerical Input (Range Check)

age = int(input("Enter your age: ")) if (age >= 18 and age <= 65): print("You are of working age.") elif (age >= 0 and age < 18): print("You are a minor.") else: print("Invalid age (or retired/senior).") # Catches > 65 and negatives

Better version with Python chaining:

if 18 <= age <= 65: print("Working age.")

Example 4: Complex Eligibility (Scholarship Application)

A student gets a scholarship if they have a GPA > 3.5 AND (they are an athlete OR they volunteer > 50 hours).

gpa = float(input("Enter GPA: ")) athlete = input("Are you an athlete? (yes/no): ").lower() == "yes" volunteer_hours = int(input("Enter volunteer hours: ")) if gpa > 3.5 and (athlete or volunteer_hours > 50): print("Congratulations! You qualify for the scholarship.") else: print("Sorry, you do not qualify.")

Example 5: The Empty Input Guard (Using not)

user_input = input("Enter your name: ") if not user_input: # Equivalent to: if user_input == "" print("You didn't type anything!") else: print(f"Hello, {user_input}!")

4. Common Pitfalls (Expanded and Critical!)

  1. The "String OR" Trap (The #1 Beginner Mistake)

  2. Forgetting Parentheses when Mixing and / or

  3. Misunderstanding Short-Circuiting in Assignments

  4. Confusing and / or with Everyday English

  5. Overcomplicating with not

  6. Comparing to True or False Redundantly

5. Quiz (Quick Knowledge Check)

Q1: Which logical operator requires both conditions to be True?

Answer(B) `and`

Q2: In if x != 0 and 10/x > 5, the division 10/x is always executed.

Answer(B) False – short‑circuiting prevents division when `x == 0`.

Q3: What is the output?

age = 25 country = "Canada" if age >= 18 and country == "USA" or country == "Canada": print("Eligible") else: print("Not eligible")
Answer(A) Eligible – due to precedence (`and` before `or`), the condition is `(age>=18 and country=="USA") or country=="Canada"`; the `or` makes it true because `country=="Canada"` is true.

Q4: To check if a variable score is between 50 and 100 (inclusive), the Pythonic way is if 50 <= score <= 100:, which is equivalent to if score >= 50 _____ score <= 100:. Fill in the blank.

Answer(A) `and`

Q5: What is the result of not (5 > 3)?

Answer(B) `False`

6. Hands-on Practice Exercises

Exercise 1: Loan Eligibility
Income > $30,000 AND credit score ≥ 700 → "Approved", else "Denied".

Sample Solution
income = float(input("Income: ")) credit = int(input("Credit score: ")) if income > 30000 and credit >= 700: print("Loan Approved") else: print("Loan Denied")

Exercise 2: Vowel Check
Ask for a letter. Print "Vowel" if it is one of aeiou (case‑insensitive), otherwise "Consonant".

Sample Solution
ch = input("Enter a letter: ").lower() if ch == 'a' or ch == 'e' or ch == 'i' or ch == 'o' or ch == 'u': print("Vowel") else: print("Consonant")

Exercise 3: Free Shipping
Spend > $50 OR premium member → "Free shipping", else "Shipping cost applies".

Sample Solution
amount = float(input("Total amount: ")) premium = input("Premium member? (yes/no): ").lower() == "yes" if amount > 50 or premium: print("Free shipping") else: print("Shipping cost applies")

Exercise 4: Leap Year (full logic)
Leap if divisible by 400, or divisible by 4 and not by 100.

Sample Solution
year = int(input("Year: ")) if (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0): print("Leap year") else: print("Not a leap year")
Here is the rewritten **Exercise 5: The Safe Division Guard**, now with a detailed sample answer provided.

Exercise 5: The Safe Division Guard Ask for two numbers, a and b. Using and in a single if statement, check if b is not zero AND a is positive. If so, print a / b. Otherwise, print "Cannot compute."

Sample Solution
a = float(input("Enter first number (a): ")) b = float(input("Enter second number (b): ")) if b != 0 and a > 0: print(a / b) else: print("Cannot compute.")

Explanation:

7. Homework Assignment

Short Answer Questions

1. Why does if country == "USA" or "Canada": always evaluate to True? How do you fix it?

Sample AnswerIn Python, `or` has lower precedence than `==`, so the expression is parsed as `(country == "USA") or "Canada"`. Since `"Canada"` is a non‑empty string, it is truthy, so the whole condition is always `True`. To fix it, write `if country == "USA" or country == "Canada":`.

2. What is short‑circuit evaluation? Give an example where it prevents a runtime error.

Sample AnswerShort‑circuit evaluation means that Python stops evaluating a compound condition as soon as the final result is known. For `and`, if the left side is `False`, the right side is never evaluated. For `or`, if the left side is `True`, the right side is never evaluated. This can prevent errors: for example, `if x != 0 and 10 / x > 5:` ensures that `10/x` is only evaluated when `x` is not zero, avoiding a `ZeroDivisionError`.

3. What is operator precedence and why is it important when combining and, or, and not?

Sample AnswerOperator precedence determines the order in which parts of an expression are evaluated. In Python, `not` has the highest precedence, then `and`, then `or`. This can lead to unexpected results if you mix them without parentheses. Using parentheses `()` makes the intended grouping explicit and is considered best practice.

Essay Question

4. Explain the difference between and and or with real‑life examples. How would you use not to invert a condition? Give at least two examples of each.

Sample Answer`and` requires that all conditions are `True`. For example, "You can enter the club if you are over 21 AND you have an ID." `or` requires at least one condition to be `True`. For example, "You get a discount if you are a student OR you are a senior citizen." `not` inverts a condition: "If you are NOT logged in, show the login page." Another `not` example: "If the file is NOT empty, process it." Using these operators, we can build complex decision logic that mirrors everyday rules.

Code Predictor (No Computer!)

Write down the exact output or error for each snippet.

Snippet 1:

x = 10 if x > 5 and x < 15: print("In range") else: print("Out of range")
Answer
In range

Explanation: The condition x > 5 and x < 15 checks if x is between 5 and 15 (exclusive). 10 > 5 is True and 10 < 15 is True. Since both conditions are True, the overall and evaluates to True, and the if block runs.

Snippet 2:

temperature = 30 is_sunny = True if temperature > 25 or is_sunny: print("Good weather") else: print("Bad weather")
Answer
Good weather

Explanation: The condition temperature > 25 or is_sunny checks if at least one is True. 30 > 25 is True, so the or condition is satisfied immediately (short‑circuiting occurs). The if block runs and prints "Good weather". Even though the second part isn't evaluated, the result is already known.

Snippet 3 (Tricky):

country = "Mexico" if country == "USA" or "Canada": print("North America") else: print("Other")
Answer
North America

Explanation: This is the classic string or trap! Due to operator precedence, the expression is evaluated as (country == "USA") or ("Canada"). Since "Canada" is a non‑empty string, it is truthy. So the condition becomes False or True, which is True, regardless of the value of country. Therefore, the if block always runs.

Corrected version would be: if country == "USA" or country == "Canada":

Snippet 4:

logged_in = False if not logged_in: print("Please log in.") else: print("Welcome!")
Answer
Please log in.

Explanation: The not operator reverses the Boolean value. logged_in is False, so not False becomes True. The if block runs and prints "Please log in.".

Snippet 5 (Short-circuit):

x = 5 y = 0 if x > 0 or y > 0: print("A") if x == 5 and y / 0 > 0: # Careful! print("B")
Answer
A Error: ZeroDivisionError - division by zero

Explanation:

Key takeaway: and does NOT short‑circuit when the first part is True – it must evaluate the second part.

Bug Hunter

Identify the error(s) in each code block. Explain why it's wrong and write the corrected version.

Buggy Code 1:

age = 22 has_license = False if age >= 18 and has_license == True: print("Can drive") else: print("Cannot drive") # Wait, this actually works, but there is a stylistic error. Can you make it more Pythonic?
Answer

Stylistic Issue: Comparing a Boolean variable directly to True or False is redundant and considered un‑Pythonic.

Why it works: The code runs correctly because has_license == True evaluates to False (since has_license is False), so the condition becomes age >= 18 and False, which is False. The else block prints "Cannot drive".

More Pythonic Version:

age = 22 has_license = False if age >= 18 and has_license: print("Can drive") else: print("Cannot drive")

Here, has_license is already a Boolean, so we use it directly.

Buggy Code 2 (Logical Error):

fruit = "Apple" if fruit == "Apple" or "Orange": print("It's a common fruit.") else: print("It's exotic.") # This always prints "It's a common fruit." even if fruit is "Banana". Fix it!
Answer

Error: This is the string or trap. The expression fruit == "Apple" or "Orange" is parsed as (fruit == "Apple") or ("Orange"). Since "Orange" is a non‑empty string, it is truthy, so the condition is always True.

Corrected Code:

fruit = "Apple" if fruit == "Apple" or fruit == "Orange": print("It's a common fruit.") else: print("It's exotic.")

Alternative (using in):

if fruit in ["Apple", "Orange"]: print("It's a common fruit.") else: print("It's exotic.")

Buggy Code 3 (Parentheses needed):

age = 20 student = True if age > 18 and student or age < 12: discount = 0.2 else: discount = 0.0 print(discount) # The goal: Give discount if (age > 18 AND student) OR age < 12. # Is the current code correct? Test with age=20, student=True (works). Test with age=10, student=False (should give discount, but current logic? age>18 False, student False, age<12 True -> Actually, it works due to and/or precedence, but it's risky. Let's rewrite it clearly with parentheses).
Answer

Issue: The code technically works due to Python's operator precedence (and has higher precedence than or), so the condition is evaluated as (age > 18 and student) or age < 12. For the test cases:

Why it's risky: The logic is not obvious to someone reading the code. It's easy to misinterpret, and future modifications might break it.

Corrected Code with explicit parentheses:

age = 20 student = True if (age > 18 and student) or age < 12: discount = 0.2 else: discount = 0.0 print(discount)

The parentheses make the intention crystal clear.

Buggy Code 4:

score = 85 if 80 <= score <= 90: print("B grade") else: print("Other") # This works, but what if we want to use 'and' to be explicit? Rewrite it using 'and'!
Answer

Goal: Rewrite the Python range check using explicit and.

Corrected Code:

score = 85 if score >= 80 and score <= 90: print("B grade") else: print("Other")

Explanation: Python's chained comparison 80 <= score <= 90 is just syntactic sugar for score >= 80 and score <= 90. The explicit version is often clearer for beginners.

Write Complete Programs

Write a Python script for each task. Test your code with different inputs.

Task 1: The University Admissions System A university admits a student if:

Sample Solution
gpa = float(input("Enter GPA: ")) sat = int(input("Enter SAT score: ")) extracurriculars = input("Outstanding extracurriculars? (yes/no): ").lower() if gpa >= 3.0 and (sat >= 1200 or extracurriculars == "yes"): print("Admitted") else: print("Not Admitted")

Task 2: The Triangle Validator Write a program that asks for the lengths of three sides of a triangle (a, b, c). A triangle is valid if the sum of any two sides is greater than the third side. (Use and to combine three conditions: a + b > c, a + c > b, and b + c > a). Print "Valid triangle" or "Invalid triangle".

Sample Solution
a = float(input("Enter side a: ")) b = float(input("Enter side b: ")) c = float(input("Enter side c: ")) if (a + b > c) and (a + c > b) and (b + c > a): print("Valid triangle") else: print("Invalid triangle")

Task 3: The Insurance Premium Calculator A company calculates premiums based on:

Sample Solution
age = int(input("Enter age: ")) experience = int(input("Enter driving experience (years): ")) if (18 <= age <= 25) and experience > 2: premium = 500 elif (26 <= age <= 40) and experience > 5: premium = 300 else: premium = 1000 print(f"Premium: ${premium}")

Task 4: The Online Order Validator Write a program that asks the user for:

Sample Solution
quantity = int(input("Enter quantity: ")) price = float(input("Enter price per item: ")) member = input("Are you a member? (yes/no): ").lower() total = quantity * price if quantity > 10 or (price > 100 and member == "yes"): total *= 0.9 # Apply 10% discount print(f"Discount applied! Final price: ${total:.2f}") else: print(f"Final price: ${total:.2f}")

Challenge Task: The Rock-Paper-Scissors Advanced Validation Write a program that asks the user for their move ("rock", "paper", "scissors"). Use if-elif-else and logical operators to check:

  1. If the input is not one of the three options, print "Invalid move!".
  2. If the input is "rock" or "scissors", print "You chose a non-paper move.".
  3. If the input is "paper", print "You chose paper.".
Sample Solution
move = input("Enter rock, paper, or scissors: ").lower() if not (move == "rock" or move == "paper" or move == "scissors"): print("Invalid move!") elif move == "rock" or move == "scissors": print("You chose a non-paper move.") elif move == "paper": print("You chose paper.")

Alternative using not in (more Pythonic):

if move not in ["rock", "paper", "scissors"]: print("Invalid move!") elif move == "rock" or move == "scissors": print("You chose a non-paper move.") else: # only "paper" left print("You chose paper.")

8. Summary Checklist

Before moving to the next module, ensure you can confidently answer:

9. Quick Reference Card

# Logical Operators # and -> BOTH must be True # or -> AT LEAST ONE must be True # not -> Reverses the boolean # Syntax with Parentheses (Best Practice) if (condition_a and condition_b) or condition_c: # Do something # Common Patterns: # 1. Range Check if 18 <= age <= 65: print("Adult") # 2. Multiple Accepted Values if day in ["Saturday", "Sunday"]: # Equivalent to day == "Sat" or day == "Sun" print("Weekend") # 3. Safe Operation (using and) if denominator != 0 and numerator / denominator > 5: print("Safe") # 4. Default value using or name = input("Enter name: ") or "Guest" print(name) # If user presses Enter, name becomes "Guest" # 5. Negation if not user_logged_in: print("Please login.")

Key Takeaway for Tutorial 5: Logical operators are the glue that turns simple conditions into complex, real-world decision-making logic. Always remember:

  1. Use and when all conditions are required.
  2. Use or when any condition is acceptable.
  3. Use parentheses () to avoid ambiguity and make your code crystal clear.
  4. Beware of the string or trap (if x == "A" or "B").

You now possess all the tools to write dynamic, intelligent programs that can handle a vast array of user inputs and scenarios. Combine this with what you learned in Tutorials 1–4, and you're ready to tackle almost any logic problem in Python!

Previous | Tutorial index | Next