This presentation is inspired by Neil Ludban's use of the "or" operator in Test-Driven Development with Python at December 2017 COhPy technical meeting.
This presentation is available at 20181027-ccc-or-operator.ipynb.
In [ ]:
# meld is a great visual difference program
# http://meldmerge.org/
# the following command relies on the directory structure on my computer
# tdd-demo comes from https://github.com/james-prior/tdd-demo/
#!cd ~/projects/tdd-demo;git difftool -t meld -y 389df2a^ 389df2a
!cd ~/20181027/tdd-demo/;git difftool -t meld -y 389df2a^ 389df2a
Python's or operator has some similarities with C's || operator.
C's || operator yields an integer: 0 (false) or 1 (true).
Python "or" operator yields one of the operands. If the first operand is true, it is the result and the second operand is guaranteed to not be evaluated. If the first operand if false, the second operand is evaluated and is the result.
Note that Python returns one of the operands, not merely 0 or 1.
...
Here are most of the built-in objects considered false:
...
Objects that are not false are true.
For each of the following cells, predict the output.
During the meeting, there was much disagreement in predictions, especially in the first four cells below. That led to real learning.
In [1]:
False or False
Out[1]:
In [2]:
0 or False
Out[2]:
In [4]:
False or 0
Out[4]:
In [3]:
0 or 0
Out[3]:
In [5]:
False or True
Out[5]:
In [6]:
True or False
Out[6]:
In [7]:
True or True
Out[7]:
In [8]:
True or 1
Out[8]:
In [9]:
1 or True
Out[9]:
In [10]:
1 or 1
Out[10]:
In [11]:
1 > 2
Out[11]:
In [12]:
3 < 4
Out[12]:
In [13]:
# This kind of expression using the "or" operator is very typical,
# comprising the vast majority of use.
1 > 2 or 3 < 4
Out[13]:
In [14]:
'this' or 'that'
Out[14]:
In [15]:
'' or 'that'
Out[15]:
In [16]:
'this' or ''
Out[16]:
In [17]:
'' or ''
Out[17]:
In [18]:
'' or None
In [19]:
False or 3.14
Out[19]:
In [20]:
'False' or 3.14
Out[20]:
In [21]:
bool('False' or 3.14)
Out[21]:
In [22]:
[] or {}
Out[22]:
In [23]:
'' or []
Out[23]:
In [24]:
'' or {}
Out[24]:
In [ ]:
'' or (1, 3)
In [25]:
'' or 'False'
Out[25]:
In [26]:
'' or 'True'
Out[26]:
In [27]:
'' or True
Out[27]:
In [28]:
'' or False
Out[28]:
Python's concept of truthiness
Numerical values are false if zero and true if not zero. None is false. Sequences and collections are false if empty, and true if not empty.
In [29]:
True
Out[29]:
In [34]:
int(True), int(False), True + True, True - True, 0 + True, True + 0
Out[34]:
In [35]:
True / False
In [38]:
True / (True + True)
Out[38]:
In [39]:
True // (True + True)
Out[39]:
In [40]:
None + 0, 0 + None
In [41]:
bool(None)
Out[41]:
In [36]:
values = (
None,
0,
0.0,
0j,
(),
[],
{},
set(),
False,
True,
True + True,
(True + True + True) / True,
1,
-1,
1.e-30,
'',
'False',
'True',
[],
[None], # This fools many people.
[0],
[0.0],
[0j],
[1],
[1, 2],
[[]], # This fools many people.
[{}],
[()],
[],
(),
(None,),
(0,),
(0.0,),
(0j,),
(1,),
(1, 2),
([],),
({},),
((),),
(),
{},
{None: None},
{False: None},
{'False': None},
set(),
{None},
{0},
{0.0},
{0j},
{1},
{1, 2},
{()},
)
Slowly scroll through the output of the following cell, predicting the output of each value before scrolling to reveal the actual output.
In [37]:
for value in values:
print(repr(value), type(value))
print(bool(value))
print()
There was some confusion and disbelief that True and False are integers, so that was played with.
Some folks also did not know about the distinction between the / and // operators in Python 3, so that was played with also.
In [51]:
True + True
Out[51]:
In [52]:
True / (True + True)
Out[52]:
In [53]:
True // (True + True)
Out[53]:
Now we get to how the "or" operator was used in fizzbuzz().
In [42]:
'' or 1
Out[42]:
In [43]:
'' or 2
Out[43]:
In [44]:
'fizz' or 3
Out[44]:
In [45]:
'buzz' or 5
Out[45]:
In [46]:
'fizz' or 6
Out[46]:
In [47]:
'fizzbuzz' or 15
Out[47]:
In [48]:
'' or 16
Out[48]:
Now we get to a more serious discussion of when it is good to use the "or" operator where the operands are not merely the typical case of False or True.
The short answer is:
Use the "or" operator when it makes the code more readable.
But that begs the question.
When does using the "or" operator make the code more readable?
This is a question I have been struggling with.
Let's go back to the old code at hand.
if not output:
return str(n)
return output
It returns either output or str(n). When said that simply in English, Neil's refactoring is the most readable code. It says most simply and directly what we want.
return output or str(n)
The problem may be from the biases of experienced programmers like myself who expect the "or" operator to yield only a true or false value, like we expect from other languages such as but not limited to C. Inexperienced folks do not bring such baggage from other languages.
For myself, I have decided to absorb and use the idiom like Neil showed us. It is part of learning Python.
With a long string of "or"ed stuff, the result is the first true operand. If no operands are true, the result is the last operand.
In [49]:
False or 0 or 0j or 0.0 or [] or {} or set() or None or ()
Out[49]:
In [50]:
False or 0 or 0j or 0.0 or 'false' or [] or {} or set() or None or ()
Out[50]:
Zach reported that the "or" operator in Javascript works like Python.
This presentation concentrated on the "or" operator. The "and" operator works like you (should) expect. Explore it on your own.
In [ ]:
False and 1
In [ ]:
'False' and 1
By the way, Python objects can define their own truthiness by defining the __bool__() or __len__() methods.
Joe Shaw: The 'wat' lightning talk by Gary Bernhardt.
2018-10-28 afterthoughts
In [64]:
bool(True)
Out[64]:
In [65]:
bool(-True)
Out[65]:
In [66]:
bool(True + 1j)
Out[66]:
In [67]:
bool(True - 1j)
Out[67]:
In [68]:
bool(True + 1j**2)
Out[68]: