Python Logical Operators

Python logical operators are the glue that holds complex conditions together. Whether you are checking if a user is logged in and has the right permissions, or deciding whether a number falls within a certain range, python logical operators make it possible to combine multiple conditions into a single expression. In this tutorial you will learn how the three logical operators — and, or, and not — work in Python, when to use each one, and how Python evaluates them under the hood.

What Are Python Logical Operators

Logical operators are special keywords in Python that let you combine or modify boolean expressions. Python has exactly three logical operators:

OperatorMeaning
andTrue if both conditions are True
orTrue if at least one condition is True
notReverses the boolean value

These operators are used constantly in if statements, while loops, list comprehensions, and any place you need to make decisions based on more than one condition. Unlike comparison operators (such as ==, >, <) which compare two values, logical operators combine the results of comparisons into a final True or False answer.

The and Operator in Python

The and operator returns True only when both the left-hand side and the right-hand side conditions are True. If either one is False, the whole expression evaluates to False.

Think of it like a two-key lock — both keys must turn at the same time for the door to open. If even one key is missing, nothing happens.

age = 25
has_id = True

if age >= 18 and has_id:
    print("Entry allowed")
else:
    print("Entry denied")
Entry allowed

Here, both conditions must pass. The variable age is 25, which is greater than or equal to 18, and has_id is True — so both sides are True and the block runs.

Here is the full truth table for the and operator:

LeftRightResult
TrueTrueTrue
TrueFalseFalse
FalseTrueFalse
FalseFalseFalse
print(True and True)    # True
print(True and False)   # False
print(False and True)   # False
print(False and False)  # False
True
False
False
False

The or Operator in Python

The or operator returns True if at least one of the conditions is True. It only returns False when both conditions are False.

Think of it like a light switch with two controls in different rooms — turning on either one lights up the room.

is_weekend = False
is_holiday = True

if is_weekend or is_holiday:
    print("No work today!")
else:
    print("Time to work.")
No work today!

Even though is_weekend is False, is_holiday is True. Since at least one condition is True, the or expression evaluates to True.

Truth table for or:

LeftRightResult
TrueTrueTrue
TrueFalseTrue
FalseTrueTrue
FalseFalseFalse
print(True or True)     # True
print(True or False)    # True
print(False or True)    # True
print(False or False)   # False
True
True
True
False

The not Operator in Python

The not operator is a unary operator — it takes only one operand and flips its boolean value. If something is True, not makes it False. If it is False, not makes it True.

It is like a toggle switch — pressing it once changes the state.

logged_in = False

if not logged_in:
    print("Please log in to continue.")
else:
    print("Welcome back!")
Please log in to continue.

The variable logged_in is False, and not False becomes True, so the if block runs.

Truth table for not:

ValueResult
TrueFalse
FalseTrue
print(not True)   # False
print(not False)  # True
False
True

Combining Multiple Logical Operators

In real applications you rarely stop at just one logical operator. Python lets you chain and, or, and not together in a single expression. When you do this, Python follows a specific order of precedence: not is evaluated first, then and, then or. This mirrors how most programming languages handle logical expressions.

score = 72
passed_exam = True
has_attendance = False

if (score >= 60 and passed_exam) or has_attendance:
    print("Student passes the course")
else:
    print("Student does not pass the course")
Student passes the course

Here the parentheses ensure score >= 60 and passed_exam is evaluated together first. That inner expression is True, so the or sees True or False, which is True.

Without parentheses Python would follow natural precedence, but adding them makes intent clear and prevents bugs. Always use parentheses when mixing and with or to make your code easy to read.

Short-Circuit Evaluation in Python

Python uses short-circuit evaluation when processing logical operators. This means Python stops evaluating as soon as the final result is certain, without checking the remaining conditions.

For and: if the left side is False, Python skips the right side entirely because the result can only be False. For or: if the left side is True, Python skips the right side because the result is already True.

This behavior is not just an optimization — it has practical uses. You can guard against errors by putting a safety check on the left side.

data = []

if data and data[0] > 10:
    print("First element is greater than 10")
else:
    print("List is empty or condition not met")
List is empty or condition not met

Because data is an empty list (falsy), Python short-circuits and never tries to access data[0]. Without short-circuiting this would raise an IndexError.

You can learn more about how Python evaluates expressions in the official Python documentation on boolean operations.

Logical Operators with Non-Boolean Values

Python logical operators do not always return True or False — they return one of the actual operand values depending on which one determined the result. This is a useful and sometimes surprising feature of Python.

For and: returns the first falsy value it encounters, or the last value if all are truthy. For or: returns the first truthy value it encounters, or the last value if all are falsy.

print(0 and "hello")     # 0 — first falsy value
print(5 and "hello")     # "hello" — all truthy, returns last
print(0 or "hello")      # "hello" — first truthy value
print("" or 0)           # 0 — all falsy, returns last
print(not "")            # True — empty string is falsy, not flips to True
0
hello
hello
0
True

This behavior is used in Python idioms like providing default values:

username = ""
display_name = username or "Guest"
print(display_name)
Guest

If username is an empty string (falsy), Python uses the fallback value "Guest". This is a clean and common pattern in Python code.

Logical Operators in Loops

Python logical operators work equally well inside while loops to keep looping as long as multiple conditions are satisfied.

attempts = 0
max_attempts = 3
success = False

while attempts < max_attempts and not success:
    attempts += 1
    print(f"Attempt {attempts}")
    if attempts == 2:
        success = True

print("Done" if success else "All attempts exhausted")
Attempt 1
Attempt 2
Done

The loop continues only while both conditions hold: attempts is still under the limit and success has not yet become True. Once success flips to True, not success becomes False, and the loop exits.

Logical Operators in List Comprehensions

You can use python logical operators inside list comprehensions to filter values based on multiple conditions at once.

numbers = [1, 4, 7, 12, 15, 18, 21, 30]

divisible = [n for n in numbers if n % 3 == 0 and n % 2 == 0]
print(divisible)
[12, 18, 30]

This collects only numbers that are divisible by both 3 and 2 — meaning divisible by 6 — using the and operator inline.

filtered = [n for n in numbers if n < 5 or n > 20]
print(filtered)
[1, 4, 21, 30]

The or operator here keeps numbers that are either very small or very large, skipping the middle range.

Operator Precedence for Logical Operators

When you mix python logical operators in one expression without parentheses, Python evaluates them in this order:

  1. not (highest precedence)
  2. and
  3. or (lowest precedence)
result = True or False and not True
# Step 1: not True → False
# Step 2: False and False → False
# Step 3: True or False → True
print(result)
True

Understanding this order helps you predict what Python will do. When in doubt, use parentheses to make the grouping explicit. The Python operator precedence table in the official docs is a useful reference.

Full Working Example

This example builds a simple access control checker that uses all three python logical operators together. It evaluates whether a user can access a restricted area based on their role, age, and verification status.

def check_access(role, age, verified):
    is_admin = role == "admin"
    is_adult = age >= 18
    is_staff = role == "staff"

    if is_admin and verified:
        print(f"Full admin access granted (age: {age})")
    elif (is_staff or is_adult) and verified:
        print(f"Standard access granted for role: {role}")
    elif not verified:
        print("Access denied: account not verified")
    else:
        print("Access denied: insufficient permissions")

check_access("admin", 30, True)
check_access("staff", 16, True)
check_access("guest", 25, False)
check_access("guest", 15, True)
Full admin access granted (age: 30)
Standard access granted for role: staff
Access denied: account not verified
Access denied: insufficient permissions

The first call passes because both is_admin and verified are True. The second call goes to the elif because is_staff is True and verified is True, even though is_adult is False — or only needs one side to be True. The third call is caught by not verified. The fourth call fails all conditions because neither is_staff nor is_adult is True, and the role is guest.