question about True values

Carl Banks pavlovevidence at gmail.com
Sat Oct 28 06:24:50 EDT 2006


Steven D'Aprano wrote:
> On Fri, 27 Oct 2006 11:25:09 -0700, Carl Banks wrote:
>
> > Steven D'Aprano wrote:
> >> But in this specific instance, I don't see any advantage to explicitly
> >> testing the length of a list. Antoon might think that is sufficiently
> >> polymorphic, but it isn't. He cares whether the object has zero _length_,
> >> but for true polymorphism, he should be caring about whether the object is
> >> _empty_. Not all empty objects have zero length, or even a length at all.
> >> (E.g. binary trees.)
> >
> > Conversely, not all objects that have length consider zero-length to be
> > false.
>
> Which is why truth-testing is defined by __nonzero__ with __len__ only the
> fall-back, for convenience.

Not all objects that have a state of emptiness consider emptiness to be
false.


> > Whether you test with "if a:" or "if len(a)>0", some objects
> > are going to be denied.
>
> If a class doesn't define __nonzero__ or __len__, it should.

No, it often shouldn't.

A. It's not always desirable for empty to be false.  Numpy defines a
bunch of numeric array types that raise an exception when __nonzero__
(actually nb_nonzero in the C API) is called.  This is the correct
behavior for numpy.  It makes no sense for numpy arrays to be used in a
boolean context, but they certainly can be empty.

B. Sometimes it's impossible to determine the state of emptiness.  For
example, iterators.


> > Thing is, objects that don't have length have almost no overlapping
> > uses with lists (i.e., you'd hardly ever write a function that could
> > take an int or a list, unless you type check the argument or use only
> > object protocol stuff like id and getattr, or pass it to another
> > function that does the same).  Iterators do have overlapping uses with
> > lists, but the "if a:" doesn't work for them, so it's moot.
>
> Sure it works for iterators.
>
> >>> it = iter([0])
> >>> bool(it)
> True
> >>> it.next()
> 0
> >>> bool(it)
> False
>
> Perhaps this behaviour has changed in version 2.5, if so, I'd like to hear
> the rationalisation before I declare it a mistake.

You haven't been paying attention.

Yes, this behavior has been changed in 2.5.  The built-in iterators
always return True in 2.5.  But even in 2.4, it was not true for
iterators in general:

>>> a = []
>>> bool(x for x in a)
True

At no point could you count on an iterator returning False for empty,
unless you'd made it yourself.  Neither "if a:" nor "if len(a)>0" is a
valid test for an empty iterator.


> > P.S. binary trees do have length: it's the number of nodes, just as the
> > number of keys is the length of a dict.
>
> I don't know what you were taught, but I was taught that binary trees have
> height and breadth.

It doesn't really matter.  dicts and sets don't have a length, either.
Or if they do, it's the length of the hash table, not the number of
entries.  Weren't you taught that?  But Python uses len() to get the
number of items in a container.  Any Pythonic implementation of a
binary tree class would use len() to return the number of entries in
it.  Anything that uses indexing ought to define len(), if it can.


Overall, your objections don't really apply, since you're arguing what
ought to be whereas my argument is pragmatic.  Practically speaking, in
realistic situations, "if len(a)>0" will work for a wider range of
types than "if a:".


Carl Banks




More information about the Python-list mailing list