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.