Implicit conversion to boolean in if and while statements
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Mon Jul 16 00:03:29 EDT 2012
On Sun, 15 Jul 2012 22:15:13 -0400, Devin Jeanpierre wrote:
> For example, instead of "if stack:" or "if bool(stack):", we could use
> "if stack.isempty():". This line tells us explicitly that stack is a
> container.
isempty is not a container method.
py> container = []
py> container.isempty()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'isempty'
Your code tells us explicitly that stack is expected to be an object with
an isempty() method. What does that mean? Who knows?
calories = macdonalds.fries('large')
calories.isempty()
=> returns True
When you want to write polymorphic code to handle your stack, you end up
doing something like this:
if isinstance(stack, MyStackClass):
flag = stack.isempty()
else:
try:
# list, collections.deque, many others
flag = len(stack) == 0
except AttributeError:
try:
if sys.version < '3':
flag = not stack.__nonzero__()
else:
flag = not stack.__bool__()
except AttributeError:
# Is this even possible in Python 3?
flag = False # I guess...
# If we get here, flag is true if stack is empty.
if flag:
...
Yeah, explicit is *so much better* for readability. Can't you just *feel*
how much more readable all those irrelevant implementation details are?
If you're smart, you wrap all of the above in a function:
def isempty(stack):
# blah blah as above
But if you're *really* smart, you write to the interface and let Python
take care of the polymorphic details for you:
if not stack:
...
(Assuming that stack defines __nonzero__ or __len__ correctly, which it
better if it claims to be a container.)
It boggles my mind that people who are perfectly happy to program to an
interface or protocol when it comes to (say) iterables, numbers or even
big complex classes with dozens of methods, suddenly freak out at the
thought that you can say "if obj" and obj is duck-typed.
There's a distinct lack of concrete, actual problems from duck-typing
bools, and a heavy over-abundance of strongly-held opinion that such a
thing is self-evidently wrong.
> As far as I know, the only use of having a polymorphic boolean
> conversion is reducing the amount of typing we do.
The same could be said about *every* polymorphic function.
The benefit is not just because you don't wear out your keyboard as fast.
The benefit is the same for all other polymorphic code: it lets you write
better code faster with fewer bugs and less need for unnecessary type
restrictions.
If there are a few corner cases where you actually *need* to restrict the
type of your flags to a actual bool, well, Python gives you the tools to
do so. Just as you can restrict the type of a sequence to exactly a list
and nothing else, or a number as exactly a float and nothing else. Just
do your type tests before you start operating on the object, and reject
anything that doesn't match what you want.
But that should be the exception, not the rule.
> Generally objects
> with otherwise different interfaces are not interchangeable just because
> they can be converted to booleans, so you wouldn't lose much by being
> forced to explicitly convert to boolean with something
> interface-specific.
Until somebody writes an awesomely fast stack class in C and gives it an
is_empty() method instead of isempty, and your code can't use it because
you made unnecessary assumptions about the implementation.
--
Steven
More information about the Python-list
mailing list