The Python language supports the following operators for booleans:
| Operator | Meaning |
|---|---|
not |
unary negation |
and |
conditional AND |
or |
conditional OR |
The and and or operators are short-circuit operators, meaning that the
second operand is only evaluated if the result cannot be determined from the
value of the first operand alone. Confusing? Let’s look at some examples in this
article.
If you prefer to watch a video, click the player below. The full article follows the video.
Overview #
and
#
Suppose we are searching a list data for a given value 'X' and want the
index of that value. Python lists have a method for this, but here the goal is
to understand the concept, so we will solve it with the most basic tools of the
language. At first, let’s assume that the value we are looking for is actually
in the list:
data = ['A', 'C', 'D', 'X', 'Z']A simple way is with a while loop:
index = 0
while index < len(data) and data[index] != 'X':
index += 1
print(index)3
Notice in the previous code that we first check whether the index is less than the length of the list and only then check whether the position being examined differs from the desired value. Let’s see what happens if we swap the order of the comparison:
index = 0
while data[index] != 'X' and index < len(data):
index += 1
print(index)3
Notice that, apparently, there is no difference. But what happens if the list does not contain the value we are looking for?
Let’s redefine our list without the value 'X':
data = ['A', 'C', 'D', 'Z']Let’s run our loop again, checking first whether the index is less than the length of the list:
index = 0
while index < len(data) and data[index] != 'X':
index += 1
print(index)4
We got the value 4 for index because the whole list was traversed and the
desired value was not found. Thus, all valid indices were visited and, when the
first comparison (first operand of and) turned out to be false, the loop was
stopped. Notice that index 4 makes no sense for this list, since the largest
possible index is 3 (remember that sequences in Python start at index zero).
Now let’s see what happens when we swap the order of the operands:
index = 0
while data[index] != 'X' and index < len(data):
index += 1
print(index)---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-6-d88901ad107a> in <module>
1 index = 0
----> 2 while data[index] != 'X' and index < len(data):
3 index += 1
4 print(index)
IndexError: list index out of range
An error occurs because, when index is set to 4, the first operand is
data[4] != 'X'. Since index 4 is not valid, we get an IndexError. Notice
that Python did not evaluate the second operand, which would have prevented the
error. This is the behavior known as
short-circuit evaluation.
This behavior can be used, as we saw in this example, to avoid possible errors
in the evaluation of the second operand. Checking first whether the index is
less than the length prevents an IndexError.
What is this behavior based on? On basic Boolean
logic. The and operator, the
logical conjunction, can
only result in True if both operands are True. Thus, a first operand with
value False is already enough for the loop to stop. If this is still
confusing, take a look at truth
tables. I have even written a small
Python program to build truth tables, which you can check out
here.
To complete the article, the truth table for the and operator, generated by
the Truth Table Generator
project, is the following:
+--------------+--------------+-----------------------------+
| operand_1 | operand_2 | operand_1 and operand_2 |
|--------------+--------------+-----------------------------|
| True | True | True |
| True | False | False |
| False | True | False |
| False | False | False |
+--------------+--------------+-----------------------------+Notice that the result is True only when both operands are True. Thus, if
the first operand is False, there is no need to evaluate the second. This is
the principle behind short-circuit behavior.
or
#
Let’s look at examples for the or operator. To understand these examples, we
need to know that the interpreter treats the following cases as False:
print(bool(False)) # the keyword False itself
print(bool(None)) # the keyword None
print(bool(0)) # the integer 0 (zero)
print(bool("")) # an empty string
print(bool(())) # an empty tuple
print(bool([])) # an empty list
print(bool({})) # an empty dictionaryFalse
False
False
False
False
False
False
If you want a more historical view of this behavior, I recommend reading
PEP 285, which implemented the
bool type in the Python language.
Let’s then consider the following two situations:
nickname = ""
def executed_function():
return "Function executed"
print(nickname or executed_function())Function executed
nickname = "Chico"
print(nickname or executed_function())Chico
Again, the behaviors derive from Boolean logic. The or operator, the
logical disjunction, can
only result in False if both operands are False. Thus, a first operand with
value True is already enough for the loop to stop. That is why, in the second
case, where nickname is not an empty string, its logical value is True and
the function is not executed.
To complete the article, the truth table for the or operator, generated by the
Truth Table Generator
project, is the following:
+--------------+--------------+----------------------------+
| operand_1 | operand_2 | operand_1 or operand_2 |
|--------------+--------------+----------------------------|
| True | True | True |
| True | False | True |
| False | True | True |
| False | False | False |
+--------------+--------------+----------------------------+Compare the table with what was written to understand the behavior.
Summary of the behavior #
| Operation | Result | Notes |
|---|---|---|
x or y |
If x is False, then y, else x |
y is evaluated only if x is False |
x and y |
If x is False, then x, else y |
y is evaluated only if x is True |
not x |
If x is True, then False, else True |
not has lower priority than non-Boolean operators |
Did you like this article? It is part of the programming Drops, a set of shorter posts focused on fundamentals, covering some aspects of the Python language and of programming in general. You can read more of these articles by browsing the "drops" tag here on the site.
See you next time!