Section 4.9 “Short-circuit” Evaluation of Logical Expressions
Take a look at this program that determines a rebate, based on the average amount of orders:
Try runing the program with 10 orders totaling $500. You will get a rebate. No problem.
Now, try running the program with zero orders totaling $500. Why did that work? Why didn’t the program crash when it tried to divide by zero (the number of orders)?
The answer is that when Python processes a logical expression such as:
n_orders > 0 and total / n_orders >= 30.0
Python evaluates the expression from left to right. Because of the definition of and
, when n_orders
is zero, the expression n_orders > 0
is False
. That means the whole expression is False
regardless of whether total / n_orders >= 30.0
evaluates to True
or False
.
When Python detects that there is nothing to be gained by evaluating the rest of a logical expression, it stops its evaluation and does not do the computations in the rest of the logical expression. When the evaluation of a logical expression stops because the overall value is already known, it is called short-circuiting the evaluation.
While this may seem like a fine point, the short-circuit behavior leads to a clever technique called the guardian pattern. Consider the following code sequence in Python:
The third calculation failed because Python was evaluating (x / y)
and y
was zero, which causes a runtime error. But the second example did not fail because the first part of the expression x >= 2
evaluated to False
. Because of the short-circuit rule, the (x / y)
was not executed, and there was no error.
We can construct the logical expression to strategically place a guard evaluation just before the evaluation that might cause an error as follows:
In the first logical expression, x >= 2
is False
so the evaluation stops right away. Neither y != 0
or (x / y) > 2
is evaluated.
In the second logical expression, x >= 2
is True
but y != 0
is False
, so we never reach (x / y)
.
In the third logical expression, the y != 0
is after the (x / y)
calculation ,so the expression fails with an error.
In the second expression, we say that y != 0
acts as a guard to insure that we only execute (x / y)
if y
is non-zero.
Checkpoint 4.9.1.
x >= 2 and y != 0 and (x / y) > 2
x >= 2
Try again. This element is making sure x matches a condition.
y != 0
This element is a guard, making sure the code does not try to divide by 0.
(x / y) > 2
Try again. This element is making sure x / y
matches a condition.
and
Try again. This is a logical operator for the boolean expression.
Checkpoint 4.9.2.