and, or, not in Python: Logical Operators Explained

In Python, and is True only when both sides are true, or is True when at least one side is, and not flips a value. They’re spelled as plain English words, not && or ||:

age >= 21 and income > 50000
state == "CA" or state == "AZ"
not is_member

Every snippet below ran on Python 3.12.5; you can see the actual Windows Command Prompt output in each screenshot.

I’ll walk through the truth table, the surprising values these operators return, short-circuiting, precedence, and why NumPy needs & and | instead.

How and, or and not work in Python

You use and when every condition must hold, or when any one is enough, and not to reverse a check. The loop prints the full truth table:

age = 34
income = 72_500.00
state = "AZ"

print(age >= 21 and income > 50_000)     # both must be True
print(state == "CA" or state == "AZ")    # at least one True
print(not state == "CA")                 # flips the result

for a in (True, False):
    for b in (True, False):
        print(f"{a!s:<5} and {b!s:<5} = {a and b!s:<5}   {a!s:<5} or {b!s:<5} = {a or b}")

Output:

True
True
True
True  and True  = True    True  or True  = True
True  and False = False   True  or False = True
False and True  = False   False or True  = True
False and False = False   False or False = False
Command Prompt output of Python and, or and not on loan-style conditions plus a full truth table for and and or
and needs both sides True. or needs just one.

You’ll mostly write these inside if statements. If else in Python has plenty of real conditions built from them.

What do the and and or operators return?

Here’s the part that may surprise you: and and or don’t always return True or False. They return one of the operands, using its truthiness to decide which:

print(0 and 5)            # 0: the first falsy value
print(3 and 5)            # 5: all truthy, so the last one
print("" or "Guest")      # 'Guest': the first truthy value
print("Ana" or "Guest")   # 'Ana'
print(None or 0 or [])    # []: nothing truthy, so the last one
print(not "Ana", not "")  # not always gives True or False

input_name = ""                   # e.g. the user left the box blank
print("Hello,", input_name or "Guest")

Output:

0
5
Guest
Ana
[]
False True
Hello, Guest
Command Prompt output showing Python and and or returning operands such as 0, 5 and 'Guest' instead of booleans
or returns the first truthy value, and and returns the first falsy one. Only not always gives a bool.

That’s why name or "Guest" is a common way to supply a default. Empty strings, 0, None and empty lists all count as false; Python bool() shows how you can test any value yourself.

Short-circuit evaluation with and and or

Python stops as soon as it knows the answer, which can save you work. If the left side of and is false, or the left side of or is true, the right side never runs:

def check(label, result):
    print("  checking", label)
    return result

print("and:", check("A", False) and check("B", True))
print("or: ", check("A", True) or check("B", False))

cart = []
if cart and cart[0] > 10:          # safe: cart[0] never runs on an empty list
    print("first item over $10")
else:
    print("cart is empty or first item is small")

Output:

  checking A
and: False
  checking A
or:  True
cart is empty or first item is small
Command Prompt output of Python short-circuit evaluation where the second function is never called
Only A gets checked each time. B is skipped because the result is already decided.

I lean on this all the time as a guard. cart and cart[0] > 10 can’t raise an IndexError, because an empty list stops it before the index runs.

Operator precedence: not, and, or

not binds tightest, then and, then or. When you mix them, add parentheses so you (and the next reader) don’t have to remember that:

is_member, total, coupon = False, 120.00, True

# not binds tightest, then and, then or
print(is_member or total > 100 and coupon)         # read as: is_member or (total > 100 and coupon)
print((is_member or total > 100) and not coupon)

discount = 0
print(discount or 10)       # 10! 0 counts as False, so "or" skips it
print(discount if discount is not None else 10)    # 0, the value you meant

Output:

True
False
10
0

The second half shows the classic or trap. A real value of 0 counts as false, so discount or 10 throws it away. If 0 is a valid answer for you, check for None explicitly.

Why logical operators fail on NumPy arrays and pandas

and needs one True or False for the whole array, and NumPy refuses to guess. Use the element-wise operators &, | and ~, with each condition in parentheses:

import numpy as np

prices = np.array([4.99, 12.50, 7.25, 25.00])

try:
    print(prices[(prices > 5) and (prices < 20)])
except ValueError as err:
    print("ValueError:", err)

print(prices[(prices > 5) & (prices < 20)])     # element-wise and
print(prices[(prices < 5) | (prices > 20)])     # element-wise or
print(any(p > 20 for p in prices), all(p > 1 for p in prices))

Output:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
[12.5   7.25]
[ 4.99 25.  ]
True True
Command Prompt output of a NumPy ValueError for the and operator on arrays, fixed with the element-wise & and | operators
The same rule applies to pandas: filter with & and |, never and and or.

For plain lists, any() and all() are the loop-friendly versions of or and and. See Python any() and Python all().

Logical operators in Python: quick reference

OperatorTrue whenReturnsOther languages
andBoth sides are truthyFirst falsy operand, or the last one&&
orEither side is truthyFirst truthy operand, or the last one||
notThe value is falsyAlways True or False!
&, |Element-wise (NumPy, pandas, sets, ints)An array or a setSame

Keep building your conditions with these:

Frequently asked questions

How do you write and and or in Python?

Use the words and and or. Python doesn’t support && or ||; they’re a SyntaxError.

What’s the difference between and and & in Python?

and is a logical operator that short-circuits. & is bitwise on ints and element-wise on NumPy arrays and pandas columns.

Does Python short-circuit and and or?

Yes. The right side is skipped when the left side already decides the result.

Why does 0 or 5 return 5?

or returns the first truthy operand. 0 is falsy, so it moves on and returns 5.

Which runs first, and or or?

and has higher precedence, so a or b and c means a or (b and c).

Where are the exact rules documented?

See the boolean operations section of the Python language reference.