How Python Boolean Operators Work
Sometimes how logical operators work aren't quite as obvious as we might think, especially across different languages. This article has a look at the AND and OR operators in Python and some of their nuances.
Join the DZone community and get the full member experience.
Join For FreeTo start, I’ll give an update on my video series. I’ve recorded my first episode, but I’ve had a ton of troubles when trying to edit it. The application keeps crashing, which is okay, since it recovers most of what I did, but it does grow tedious. I’ve also decided to start the editing over due to a few factors. Lastly, I’ve started recording a series of videos with my best friend for his gaming YouTube channel. All of that together has led me to put off the my video series for a while and get back to writing on the blog. I’ll get back to the video series when I’ve finished recording with my friend. It could take a while.
Python Boolean Operator Confusion
A while back, I stumbled upon a post asking about the how the following lines could possibly right:'a' == 'b' or 'a'
returns 'a'
'a' == 'a' and 'b'
returns 'b'
He had a few other lines that did what you might expect, returning True
and False
. But why do these and
and or
operators not always return boolean values? To answer that, I’d like to dig into Python’s history.
A History of Boolean in Python
In the beginning, Python didn’t have a boolean type. This may shock you, but Python is actually getting pretty far up there in age, and back when it was created, boolean types weren’t “standard”. Often, 1
and 0
were substitutes for truth and fallacy, respectively. That, coupled with Python’s ability for objects to express “truthiness”, “false” objects were generally representative of “empty” values.
But then PEP 285 came out; True
and False
were added into the language, but Python still kept its “truthiness” concept. Really, True
and False
are pretty much (maybe actually) just constant names for 1
and 0
.
So, how does this translate to how the earlier lines work?
How the Operators Work
First thing you need to realize (and probably already do) is that and
and or
are short-circuiting operators, which means they skip doing work that they don’t have to do. To explain, let’s look at the truth tables of the operators:
a | b | a OR b |
false | false | false |
true | false | true |
false | true | true |
true | true | true |
AND
a | b | a AND b |
false | false | false |
true | false | false |
false | true | false |
true | true | true |
Now, look closely at those tables. In the OR table, any time that a is true, the final result will be true. This means, that when a is true, you don’t even need to find out what b is in order to know the final result. The only time you need to know what b is is when a is false. Interestingly, in both cases, the final result is equal to b. This can be shortened “if a is true, the answer is equal to a; otherwise, it’s equal to b”.
AND has a similar property, but a little different. It can be worded as “if a is false, the answer is equal to a, otherwise it’s equal to b”.
Applying Truthiness
Let’s apply the same idea with truthiness and turn and
and or
into function definitions:
def and(a, b):
if a: # checks truthiness
return a
else:
return b
def or(a, b):
if not a:
return a
else:
return b
Finally, not
takes the result of bool(a)
and returns the opposite one.
So, when we see 'a' == 'b' or 'a'
, we know that it returns 'a'
because the left side of or
is false, meaning we return the right side. And we know that 'a' == 'a' and 'b'
returns 'b'
because the left side of and
is true, meaning that we again return the right side.
What Good Is This?
So what does this do for us? Firstly, it gave Python backwards compatibility to the time before true boolean values. Secondly, it provides ways of quickly setting a default value:
def someFunc(param=None):
param = param or []
…
In this instance, we want the default value for param
to be an empty list, but using mutable types like that as the default in the parameter list is dangerous, so we default to None
and use that as our falsey value to determine whether something was provided by the caller or not. This isn’t perfect, though. If the caller provides something else that’s falsey, it will be ignored in favor of the default value. This is more properly written with Python’s conditional expression:
param = [] if param is None else param
But there can still be times where the boolean operations could be useful in this way.
Summary
Hopefully you understand how Python does booleans a little better now. Javascript is quite similar in this respect, so don’t think that Python is the odd duck (get it? Because of ‘duck typing’).
Next week, we’ll delve into why 'a' in 'abc' == True
returns False
.
Published at DZone with permission of Jake Zimmerman, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments