Python Logical Operators: and, or, not Explained
Python logical operators combine conditions and return a result based on truthiness, not just true and false values. Use and when both conditions must be true, or when either condition can be true, and not when you want to flip a condition. This article shows how they work, why short-circuiting matters, and where beginners often get confused.
Difficulty: Beginner
Helpful to know first: basic variables, comparison operators like == and >, and how if statements use conditions.
How Python Logical Operators Work
Python has three logical operators: and, or, and not. They are used to build larger conditions from smaller ones, such as checking whether a number is in a range or whether a user is logged in and has permission.
Unlike many languages, Python does not always force these operators to return only True or False. Instead, and and or return one of their operands, and that operand is chosen using truthiness. That is why these operators are useful both in conditions and in normal expressions.
age = 20
has_id = True
if age >= 18 and has_id:
print("Allowed in")
else:
print("Not allowed")
# Output: Allowed inIn this example, both parts of the condition must be true. The first part checks the age, and the second part checks the ID flag. Because both are true, the whole if condition is true.
Working With and, or, and not
The three operators follow simple rules:
- and returns the first false value it finds, or the last value if all are true.
- or returns the first true value it finds, or the last value if all are false.
- not always returns a Boolean value, True or False.
This makes the operators useful for conditions, defaults, and simple checks. The examples below move from basic Boolean logic to realistic Python patterns.
Using and to require two conditions
Use and when both conditions must be true. A common example is a range check.
temperature = 22
if 18 <= temperature and temperature <= 25:
print("Comfortable")
else:
print("Not comfortable")
# Output: ComfortableThis reads naturally: the temperature must be at least 18 and at most 25. The same pattern appears in validation code, permission checks, and loops that filter data.
Using or to accept either condition
Use or when one true condition is enough. This is common when you want to accept multiple valid inputs.
is_weekend = False
is_holiday = True
if is_weekend or is_holiday:
print("No school")
else:
print("School day")
# Output: No schoolOnly one side needs to be true. Here, is_holiday is true, so the full expression is true even though is_weekend is false.
Using not to flip a condition
Use not when you want the opposite meaning of a condition. This is useful for readable conditions such as “if not empty” or “if not logged in.”
is_empty = False
if not is_empty:
print("There is data")
else:
print("No data")
# Output: There is dataThe not operator changes False to True and True to False. It always produces a Boolean result.
Using logical operators with truthy and falsy values
Python lets many values act as true or false in a condition. Empty strings, zero, empty containers, and None are falsy. Non-empty values are truthy.
name = "Ada"
nickname = ""
print(name and nickname)
print(name or "Anonymous")
# Output:
#
# AdaThe first line returns the empty string because and stops at the first falsy value. The second line returns name because it is truthy, so or stops immediately.
How Python Decides What Counts as True or False
Python checks an object's truth value when it evaluates logical operators and if statements. Most built-in types follow simple rules. Zero is false, empty sequences and collections are false, and None is false. Most other values are true.
This truthiness rule matters because logical operators do not require operands to be actual Boolean values. A list, string, number, or object can all be used in a logical expression.
print(bool(0))
print(bool(3))
print(bool(""))
print(bool("Python"))
# Output:
# False
# True
# False
# TrueKnowing this helps you read expressions like items and items[0] or user_input or default_value. The operator uses truthiness to decide what to return.
Short-Circuiting: Why Python Sometimes Stops Early
Python does not always evaluate both sides of a logical expression. This behavior is called short-circuiting. It matters because it can save work and prevent errors.
With and, Python stops as soon as it finds a false value. With or, Python stops as soon as it finds a true value.
def left():
print("left")
return False
def right():
print("right")
return True
print(left() and right())
# Output:
# left
# Falseright() is never called here because left() already returned False. That is why short-circuiting is useful for guarding code that might fail.
user = None
if user and user["name"] == "Ada":
print("Matched")
else:
print("No match")
# Output: No matchBecause user is None, Python never tries to access user["name"]. That prevents a TypeError and makes the check safe.
Operator Precedence: Why Some Expressions Need Parentheses
Python evaluates not before and, and and before or. This order often surprises beginners.
print(not True and False)
print((not True) and False)
# Output:
# False
# FalseIn this case the results match, but the grouping is still important. Without parentheses, Python reads the first line as (not True) and False.
Here is a case where precedence changes the result:
print(True or False and False)
print((True or False) and False)
# Output:
# True
# FalsePython reads the first line as True or (False and False), not as (True or False) and False. Parentheses make the meaning obvious and prevent logic bugs.
Predict the Output
Short-circuiting with and
What does this print?
def check(value):
print(value)
return value > 0
print(check(-1) and check(2))Show answer
Answer: It prints -1 and then False.
Why: check(-1) prints -1 and returns False because -1 > 0 is false. Since and stops at the first false value, Python never calls check(2).
# Output:
# -1
# FalseReturning values with or
What does this print?
name = ""
display_name = name or "Guest"
print(display_name)Show answer
Answer: It prints Guest.
Why: The empty string is falsy, so or returns the right-hand value. This pattern is common for fallbacks and defaults.
# Output:
# GuestCommon Mistakes With Python Logical Operators
Using and when you meant or
Beginners often write a condition that is too strict. They want to allow either option, but they accidentally require both.
Problem: This condition can never be true for a single number because a value cannot be less than 5 and greater than 10 at the same time.
number = 7
if number < 5 and number > 10:
print("In range")Fix: Use or for either side, or use a chained comparison for a real range check.
number = 7
if number < 5 or number > 10:
print("Outside range")
else:
print("Inside range")
# Output: Inside rangeThe fixed version matches the actual meaning of the check.
Forgetting that not needs one value, not two
The not operator flips one condition. It does not compare two values.
Problem: This code tries to use not like an equality test, which is not valid Python syntax.
x = 3
y = 4
if x not y:
print("Different")Fix: Use != to test inequality, or not with a full comparison.
x = 3
y = 4
if x != y:
print("Different")
# Output: DifferentThe corrected version uses the comparison operator designed for inequality.
Relying on truthiness when you need an exact Boolean
Sometimes a value such as 0 or an empty string is valid data, not a missing value. If you use or to supply a default, you may replace a real value by mistake.
Problem: This code treats 0 as if it were missing, so it chooses the default value instead of keeping the real input.
quantity = 0
result = quantity or 10
print(result)Fix: Check explicitly for None when zero is a meaningful value.
quantity = 0
result = 10 if quantity is None else quantity
print(result)
# Output: 0The corrected version keeps zero because it checks for missing data instead of falsy data.
Find the Bug
A teammate wrote this code to print a safe username. It looks reasonable, but it has a subtle bug. Find it.
user = {"name": ""}
name = user.get("name") or "Guest"
print(name)Show answer
What is wrong: The code treats an empty string as missing data. If an empty string is a valid username, the fallback to "Guest" changes the real value.
Why it matters: or uses truthiness, so it replaces any falsy value, including "", 0, and False. That is correct for many defaults, but not for every input field.
Fixed code: Check specifically for None if missing data is the only case that should use the default.
user = {"name": ""}
name = "Guest" if user.get("name") is None else user.get("name")
print(name)
# Output:
# The fix works because it preserves empty strings and only replaces a missing value.
When to Use Logical Operators and When to Use Something Else
Logical operators are the right tool when you need a Boolean decision or a truthy/falsy choice. They are not the best tool for every kind of test.
| Need | Use this | Why |
|---|---|---|
| Both conditions must be true | and | It combines two checks into one decision. |
| Either condition may be true | or | It accepts the first true value. |
| Flip a condition | not | It changes true to false and false to true. |
| Test exact equality or inequality | ==, != | These compare values directly instead of using truthiness. |
| Check a range | Chained comparison like 0 < x < 10 | It is clearer than combining two comparisons with and. |
A common mistake is to force logical operators into jobs that comparison operators already do better. For example, use x == 5 to check whether x equals 5. Do not write x and 5 if you really mean equality.
Predict the Output
Comparing and with returned values
What does this print?
print("cat" and "dog")
print("" or "fallback")Show answer
Answer: It prints dog and then fallback.
Why: and returns the second operand when the first one is truthy. or returns the second operand when the first one is falsy. The result is not always a Boolean.
# Output:
# dog
# fallbackTry It Yourself
Write a program that asks Python to decide whether a number is inside the inclusive range from 10 to 20.
- Set a variable named number to 15.
- Use one if statement with logical operators.
- Print "Inside" if the number is between 10 and 20, inclusive.
- Otherwise print "Outside".
Expected output:
InsideHint: The condition should use two comparisons joined by and.
Show solution
number = 15
if 10 <= number and number <= 20:
print("Inside")
else:
print("Outside")Summary
- and needs both sides to be truthy to continue.
- or needs only one truthy side.
- not flips a condition and returns a Boolean result.
- Python uses truthiness, so operands do not need to be actual Booleans.
- and and or short-circuit, so Python may skip the right-hand side.
- Use parentheses when precedence could make the meaning unclear.
Next, learn Python comparison operators so you can build the individual conditions that logical operators combine.