class with __len__ member fools boolean usage "if x:" ; bad coding style?

Peter Otten __peter__ at
Tue Jun 29 20:34:21 CEST 2004

Heiko Wundram wrote:

> Am Dienstag, 29. Juni 2004 07:59 schrieb Peter Otten:
>> Now you have an object that neither behaves consistently as a boolean nor
>> as a sequence, I fear you in for even subtler bugs...
> That isn't necessarily true... Given the following example, I'd say what
> __nonzero__ and __len__ implement is quite understandable, and if
> documented, the programmer isn't in for any bug:
> <code>
> import time
> class ID(object):
> def __init__(self):
> self.__id = "test"
> def __len__(self):
> return len(self.__id)
> class Host(ID):
> def __init__(self):
> self.__timeout = time.time() + 30
> def __nonzero__(self):
> return self.__timeout >= time.time()
> </code>
> nonzero and len implement something completely different, where __len__ is
> an operator on the underlying ID of a Host, and __nonzero__ is an operator
> on the Host itself, to check whether the Host has timed out.

In Python, you don't normally check for a timeout (google for LBYL), you'd
rather throw an exception. This avoids problems like

h = Host()
if h:
   h.someOperation() # fails due to timeout

> It doesn't make sense to have __nonzero__ refer to the ID (which is always
> nonzero, a string), and it neither makes sense to have __len__ refer to
> the Host (which doesn't have a length), so the situation here is pretty
> clear (IMHO).

A __len__() without a __getitem__() method doesn't make sense to me. But
maybe your example is just too terse...
> But, as always, documentation is better than guessing. ;)

No amount of documentation can heal an unintuitive API.
The convention of using bool(o) as an abbreviation of o.isValid() for
non-sequences and of len(o) != 0 for sequences seems natural to me. Mixing
these two meanings or even adding "was this parameter provided" as a third
one will result in highly ambiguous code that is bound to break.


More information about the Python-list mailing list