Innovate | Connect | Transform
ContactService statusUSD $

GICT knowledge base

Python Logical Operators: and, or, not and Short-Circuiting

Published

Python

Python’s logical operators are and, or and not. They test truth values, but only not always returns a Boolean. and and or return one of their operands, and can skip evaluating the other operand.

The following self-contained examples were executed with Python 3.12.14. They use sample values rather than login or permission checks.

Read the Boolean truth table

With Boolean operands, and is true when both inputs are true; or is true when at least one is true. not reverses the truth value.

a b a and b a or b
False False False False
False True False True
True False False True
True True True True
rows = []
for a in [False, True]:
    for b in [False, True]:
        rows.append((a, b, a and b, a or b))

assert rows == [
    (False, False, False, False),
    (False, True, False, True),
    (True, False, False, True),
    (True, True, True, True),
]
assert (not True) is False
print(rows)

Understand truthiness and returned operands

Common false values include None, numeric zero, and empty strings or containers. Non-empty strings are truthy even if their text says "False". Custom classes can define their own truth behavior. Use bool(value) when you specifically need a Boolean result.

a and b returns a if it is falsey, otherwise b. a or b returns a if it is truthy, otherwise b. A chain of alternatives returns the last operand if all earlier operands are falsey.

assert ("web" and 443) == 443
assert ([] and "unused") == []
assert ("web" or "fallback") == "web"
assert ("" or 0 or None) is None
assert bool("False") is True
assert (not []) is True
assert all(not value for value in [None, 0, 0.0, "", [], {}, set()])
print(bool("False"))

Use short-circuit evaluation deliberately

The second operand is evaluated only if needed. This can guard a calculation, but should not hide important side effects. Here the function records whether it was called, so the skipped calls are observable rather than assumed.

calls = []

def record():
    calls.append("called")
    return "result"

assert (False and record()) is False
assert (True or record()) is True
assert calls == []
assert (True and record()) == "result"
assert calls == ["called"]

denominator = 0
safe_to_divide = denominator != 0 and 10 / denominator > 2
assert safe_to_divide is False
print(calls)

Parentheses can change the answer

Comparisons bind more tightly than not, which binds more tightly than and, then or. Precedence determines grouping; it does not make every not expression execute before all other work. Use parentheses to show the intended grouping, not to disguise a change in logic.

x = 8
y = 12
first = not (x > 5) and (y < 10)
second = not ((x > 5) and (y < 10))
assert first is False
assert second is True

ready = True
paused = False
urgent = True
assert (ready and not paused or urgent) is True
assert ((ready and not paused) or urgent) is True
print(first, second)

Preserve meaningful zero and False values

value or default replaces every falsey value, not only missing values. If zero means no retries, silently replacing it with three retries changes the setting. Compare with None when that is your missing-value marker.

def retries_or_default(value):
    return 3 if value is None else value

assert retries_or_default(None) == 3
assert retries_or_default(0) == 0
assert retries_or_default(5) == 5
assert (0 or 3) == 3
print(retries_or_default(0))

Write each comparison, or use membership

state == "ready" or "queued" does not compare state twice. The non-empty string makes the condition truthy when the first comparison is false. For alternatives, use membership; for a numeric interval, use a chained comparison or two comparisons joined with and.

state = "failed"
incorrect = state == "ready" or "queued"
correct = state in {"ready", "queued"}
assert incorrect == "queued"
assert bool(incorrect) is True
assert correct is False

within = [2 <= hour < 5 for hour in [1, 2, 4, 5]]
assert within == [False, True, True, False]
print(correct, within)

Use and/or, not bitwise &/|, for ordinary Boolean conditions. Libraries that overload operators, such as array libraries, have their own rules. Also avoid treating the presence of an email address, username or API-key string as proof of authentication.

Verification: All six blocks and their assertions ran independently, including short-circuit call counts. References: Boolean expression rules and truth-value testing. Continue with if, elif and else.

Related guides

Account services are unavailable until the production backend is configured.