by Christoph Schiessl on Python
Recently, I have written about various topics related to Booleans in Python, such as the built-in any()
/ all()
functions and the Standard Truth Testing Procedure. But, what I did not yet explain about are three boolean operators themselves:
not
keyword,and
keyword, andor
keyword.not
OperatorThe not
operator is the simplest of all the boolean operators. Firstly, it's a unary operator, which takes only a single operand as input. Secondly, the operator's evaluation result is always True
or False
(i.e., an instance of the bool
class). Thirdly, there is no short-circuiting behavior — the whole concept isn't even applicable to unary operators.
Python 3.12.2 (main, Feb 17 2024, 11:13:07) [GCC 13.2.1 20230801] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class IAmTrue:
... def __init__(self, label): self._label = label
... def __repr__(self): return f"IAmTrue(label='{self._label}')"
... def __bool__(self):
... print("IAmTrue.__bool__() has been called.")
... return True
...
>>> class IAmFalse:
... def __init__(self, label): self._label = label
... def __repr__(self): return f"IAmFalse(label='{self._label}')"
... def __bool__(self):
... print("IAmFalse.__bool__() has been called.")
... return False
...
>>> not IAmTrue('1st')
IAmTrue.__bool__() has been called.
False
>>> not IAmFalse('1st')
IAmFalse.__bool__() has been called.
True
and
OperatorNext up is the and
operator, which is more interesting because it's a binary operator, meaning it takes two operands as input. The result is that expressions like x and y
evaluate to x
if and only if x
converts to False
; otherwise, they evaluate to y
. This behavior is known as short-circuiting because — as long as the first operand converts to False
— it doesn't even consider the second operand. Furthermore, note that, in all cases, only the first operand is ever truth-tested!
Python 3.12.2 (main, Feb 17 2024, 11:13:07) [GCC 13.2.1 20230801] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class IAmTrue:
... def __init__(self, label): self._label = label
... def __repr__(self): return f"IAmTrue(label='{self._label}')"
... def __bool__(self):
... print("IAmTrue.__bool__() has been called.")
... return True
...
>>> class IAmFalse:
... def __init__(self, label): self._label = label
... def __repr__(self): return f"IAmFalse(label='{self._label}')"
... def __bool__(self):
... print("IAmFalse.__bool__() has been called.")
... return False
...
>>> IAmFalse('1st') and IAmFalse('2nd') # short-circuit to 1st
IAmFalse.__bool__() has been called.
IAmFalse(label='1st')
>>> IAmFalse('1st') and IAmTrue('2nd') # short-circuit to 1st
IAmFalse.__bool__() has been called.
IAmFalse(label='1st')
>>> IAmTrue('1st') and IAmFalse('2nd')
IAmTrue.__bool__() has been called.
IAmFalse(label='2nd')
>>> IAmTrue('1st') and IAmTrue('2nd')
IAmTrue.__bool__() has been called.
IAmTrue(label='2nd')
or
OperatorLast but not least is the or
Operator, also a binary operator. The result is that expressions like x or y
evaluate to x
if and only if x
converts to True
; otherwise, they evaluate to y
. This is again short-circuiting behavior: As long as the first operand converts to True
, it doesn't even consider the second operand. Furthermore, note that, in all cases, only the first operand is ever truth-tested!
Python 3.12.2 (main, Feb 17 2024, 11:13:07) [GCC 13.2.1 20230801] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class IAmTrue:
... def __init__(self, label): self._label = label
... def __repr__(self): return f"IAmTrue(label='{self._label}')"
... def __bool__(self):
... print("IAmTrue.__bool__() has been called.")
... return True
...
>>> class IAmFalse:
... def __init__(self, label): self._label = label
... def __repr__(self): return f"IAmFalse(label='{self._label}')"
... def __bool__(self):
... print("IAmFalse.__bool__() has been called.")
... return False
...
>>> IAmFalse('1st') or IAmFalse('2nd')
IAmFalse.__bool__() has been called.
IAmFalse(label='2nd')
>>> IAmFalse('1st') or IAmTrue('2nd')
IAmFalse.__bool__() has been called.
IAmTrue(label='2nd')
>>> IAmTrue('1st') or IAmFalse('2nd') # short-circuit to 1st
IAmTrue.__bool__() has been called.
IAmTrue(label='1st')
>>> IAmTrue('1st') or IAmTrue('2nd') # short-circuit to 1st
IAmTrue.__bool__() has been called.
IAmTrue(label='1st')
Finally, we have to talk about precedence. Here are the three boolean operators ordered from highest to lowest precedence:
(1) not
, (2) and
, (3) or
. As always, I want to demonstrate what I'm saying ... so, to prove that not
has higher precedence than and
/or
, we need two boolean variables:
for x in [True, False]:
for y in [True, False]:
# Proof: `not` has higher precedence than `and`
assert (not x and y) == ((not x) and y)
assert (x and not y) == (x and (not y))
# Proof: `not` has higher precedence than `or`
assert (not x or y) == ((not x) or y)
assert (x or not y) == (x or (not y))
And three variables to prove that and
has higher precedence than or
:
for x in [True, False]:
for y in [True, False]:
for z in [True, False]:
# Proof: `and` has higher precedence than `or`
assert (x and y or z) == ((x and y) or z)
assert (x or y and z) == (x or (y and z))
If you run these two scripts, you don't get any AssertionError
s, proving that precedence works, as I said before. Anyway, that is everything for today! Thank you for reading, and see you soon!
I send two weekly emails on building performant and resilient Web Applications with Python, JavaScript and PostgreSQL. No spam. Unscubscribe at any time.
bool()
Class
Learn about boolean values in Python and the standard truth testing procedure. Understand how objects are converted to True
or False
.
By Christoph Schiessl on Python
callable()
Function
Learn about the callable()
function in Python. This article explains how everything in Python is potentially callable, including classes and instances.
By Christoph Schiessl on Python
any()
Function
Learn how to use the built-in any()
function in Python to determine if any element in an iterable
is True
, with implementation and performance insights.
By Christoph Schiessl on Python