To 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' and 'b' returns
He had a few other lines that did what you might expect, returning
False. But why do these
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,
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;
False were added into the language, but Python still kept its “truthiness” concept. Really,
False are pretty much (maybe actually) just constant names for
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
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|
|a||b||a AND b|
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”.
Let’s apply the same idea with truthiness and turn
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
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.
Next week, we’ll delve into why
'a' in 'abc' == True returns