3.4. Arbitrary Types Treated As BooleanΒΆ

The following section would merely be an advanced topic, except for the fact that many common mistakes have their meaning changed and obscured by the Boolean syntax discussed.

You have seen how many kinds of objects can be converted to other types. Any object can be converted to Boolean (type bool). Read the examples shown in this Shell sequence:

>>> bool(2)
True
>>> bool(-3.1)
True
>>> bool(0)
False
>>> bool(0.0)
False
>>> bool(None)
False
>>> bool('')
False
>>> bool('0')
True
>>> bool('False')
True
>>> bool([])
False
>>> bool([0])
True

The result looks pretty strange, but there is a fairly short general explanation: Almost everything is converted to True. The only values among built-in types that are interpreted as False are

  • The Boolean value False itself
  • Any numerical value equal to 0 (0, 0.0 but not 2 or -3.1)
  • The special value None
  • Any empty sequence or collection, including the empty string ('', but not '0' or 'hi' or 'False') and the including empty list ([], but not [1,2, 3] or [0])

A possibly useful consequence occurs in the fairly common situation where something needs to be done with a list only if it is nonempty. In this case the explicit syntax:

if len(aList) > 0:
    doSomethingWith(aList)

can be written with the more succinct Pythonic idiom

if aList:
    doSomethingWith(aList)

This automatic conversion can also lead to extra trouble! Suppose you prompt the user for the answer to a yes/no question, and want to accept ‘y’ or ‘yes’ as indicating True. You might write the following incorrect code. Read it:

ans = input('Is this OK? ')
if ans == 'y' or 'yes':
    print('Yes, it is OK')

The problem is that there are two binary operations here: ==, or. Comparison operations all have higher precedence than the logical operations or, and, and not. The if condition above can be rewritten equivalently with parentheses. Read and consider:

(ans == 'y') or 'yes'

Other programming languages have the advantage of stopping with an error at such an expression, since a string like 'yes' is not of type bool. Python, however, accepts the expression, and treats 'yes' as True. To test, run the example program boolConfusion.py, shown below:

ans = 'y'
if ans == 'y' or 'yes':
    print('y is OK')

ans = 'no'
if ans == 'y' or 'yes':
    print('no is OK!!???')

Python detects no error. The or expression is treated as True, since 'yes' is a non-empty sequence, interpreted as True.

The intention of someone writing

if ans == 'y' or 'yes':

presumably was that the condition meant something like

(ans == 'y') or (ans == 'yes')

This version also translates directly to other languages. Another correct Pythonic alternative that groups the alternate values together is

ans in ['y', 'yes']

which reads pretty much like English.

Be careful to use a correct expression when you want to specify a condition like this.

Things get even stranger! Enter these conditions themselves, one at a time, directly into the Shell:

'y' == 'y' or 'yes'
'no' == 'y' or 'yes'
'y' == 'y' and 'yes'
'no' == 'y' and 'yes'
'no' or 'yes'
'no' and 'yes'

The meaning of (a or b) and of (a and b) are exactly as discussed so far if each of the operands a and b are actually Boolean, but more elaborate definitions are needed if an operand is not Boolean:

val = a or b

means

if bool(a):
    val = a
else:
    val = b

and in a similar vein:

val = a and b

means

if bool(a):
    val = b
else:
    val = a

This strange syntax was included in Python to allow code like in the following example program orNotBoolean.py. Read and test if you like:

defaultColor = 'red'
userColor = input('Enter a color, or just press Enter for the default: ')
color = userColor or defaultColor
print('The color is', color)

which sets color to the value of defaultColor if the user enters an empty string.

Again, this may be useful to experienced programmers, bhe syntax can certainly cause difficult bugs, particularly for beginners!

The not operator always produces a result of type bool.