Short circuit evaluation
Categories: python language intermediate python
Python has a useful feature called short circuit evaluation that acts on logical operators or
and and
.
Short circuiting with the or operator
Consider this code:
x = 5
y = 10
if x > 6 or y < 20:
print('OK')
When Python reaches the if statement, it starts evaluating the terms from left to right:
x > 6
is falsey < 20
is true- therefore the result of the
or
expression is true - the print statement executes
Now compare this code:
x = 7
y = 10
if x > 6 or y < 20:
print('OK')
x > 6
is true- therefore the result of the
or
expression is true - the print statement executes
In this case, as soon as Python discovers that x
is greater than 6, it knows that the whole or
statement is true, so it doesn't bother checking y
. It doesn't matter whether y
is less than 20 or not, it won't affect the outcome because an or
statement is always true if either of the terms is true.
Python guarantees not to evaluate the second term if the first term is true.
Short circuiting with the and operator
Short circuiting with the and
operator works in a similar way.
x = 5
y = 10
if x > 6 and y < 20:
print('OK')
In this case:
x > 6
is false- therefore the result of the
and
expression is false - the print statement doesn't execute
In this case, Python never evaluates y < 20
because it already knows the final result will be false.
In summary:
- An
or
statement stops as soon as if encounters the firstTrue
case - An
and
statement stops as soon as if encounters the firstFalse
case
Short circuiting to avoid errors
We can often use short circuit evaluation to avoid errors. A common case is checking for a value being 0 before performing a calculation:
n = 3
m = 2
if m < 1/n:
print('m < 1/n')
This code looks alright at first glance. But what happens if n
is zero? Dividing by zero is an error, so our code would thrown an exception and stop working.
A quick way to avoid this is to use short circuiting, with the and
operator:
n = 0
m = 2
if n and m < 1/n:
print('m < 1/n')
With this new code, we have an and
expression. The first term in n
. If n
is 0, which of course counts as false, Python knows that the whole an expression is false, so it never evaluates 1/n
and there is no error.
If n
is not zero, Python evaluates the second expression as normal.
You need to take care with this technique. Although we have successfully avoided throwing a divide by zero error, we have also ignored the fact that
n
is zero. This could lead to further errors in other parts of the code.
The value of an or/and expression
You might expect the value of a logical expression to always be True
or False
, but in fact this isn't the case. Python does something more useful.
a = 0
b = 2
c = 3
x = c or a:
print(x)
You may be surprised to see it print 3.
What actually happens is that Python prints the last value it evaluates. In this case, Python evaluates c
, which has a value 3. Since this counts as true, it doesn't need to evaluate a
, so it returns the value 3.
Here are some more examples, using the same values of a
, b
and c
:
x = a or b:
print(x) #prints 2
x = b or c:
print(x) #prints 2
x = 0 or a:
print(x) #prints 0 (the result is false because 0 and a are both false)
x = a or b+c or b+a:
print(x) #prints 5 (b+c, the first true value)
Here is a real life example:
username=''
username = username or input('Enter username')
In this case, the or
statement first evaluates username
, which is an empty string, so it counts as false. It then evaluates the input
statement - that is, it calls the input
function, waits for the user to type in their name, and returns that value.
If we were to execute this statement again, later, when username
has a value, the or
expression would simply return the current value, and would not call input()
at all.
Getting a true or false value
It doesn't usually matter that a
or b
gives a value of 2 rather than True
, because it works fine in an if statement.
If you really need to, you can always use the bool()
function. bool()
converts any value to True
or False
.
See also
- List comprehensions
- Objects and variables
- Objects and identity
- Immutable objects
- Global variables
- Data types
- Lists vs tuples
- Sequences
- Named tuples
- Operators
- Walrus Operator
- For loops
- For loop using range vs iterables
- Changing the loop order
- Using enumerate in a for loop
- Using zip in a for loop
- Looping over multiple items (old article)
- Looping over selected items
- Functions
- Declaring functions
- Calling functions
- Function objects and lambdas
- Function decorators
- With statements
- Exception handling
- String functions
- Built-in functions
- Optimisation
- Optimisation good practice
- Low level code optimisation
- Structural optimisation
Join the PythonInformer Newsletter
Sign up using this form to receive an email when new content is added:
Popular tags
2d arrays abstract data type alignment and angle animation arc array arrays bar chart bar style behavioural pattern bezier curve built-in function callable object chain circle classes clipping close closure cmyk colour combinations comparison operator comprehension context context manager conversion count creational pattern data science data types decorator design pattern device space dictionary drawing duck typing efficiency ellipse else encryption enumerate fill filter font font style for loop formula function function composition function plot functools game development generativepy tutorial generator geometry gif global variable gradient greyscale higher order function hsl html image image processing imagesurface immutable object in operator index inner function input installing iter iterable iterator itertools join l system lambda function latex len lerp line line plot line style linear gradient linspace list list comprehension logical operator lru_cache magic method mandelbrot mandelbrot set map marker style matplotlib monad mutability named parameter numeric python numpy object open operator optimisation optional parameter or pandas partial application path pattern permutations pie chart pil pillow polygon pong positional parameter print product programming paradigms programming techniques pure function python standard library radial gradient range recipes rectangle recursion reduce regular polygon repeat rgb rotation roundrect scaling scatter plot scipy sector segment sequence setup shape singleton slice slicing sound spirograph sprite square str stream string stroke structural pattern subpath symmetric encryption template tex text text metrics tinkerbell fractal transform translation transparency triangle truthy value tuple turtle unpacking user space vectorisation webserver website while loop zip zip_longest