↓ Skip to main content

Short-Circuit Evaluation in Python - Boolean Operators

·1063 words·6 mins·
 Author
Author
Francisco Bustamante
Chemist, data scientist and Python programmer.
Table of Contents

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 dictionary
False
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!

Related

Logic for Programmers

·4174 words·20 mins
In programming, the word “logic” can refer to the process of designing an algorithm, to the conditional structures of the language, or to logical operators such as AND and OR. In the last two cases, we are within what is called mathematical logic.