Boolean tests [was Re: Attack a sacred Python Cow]

Heiko Wundram modelnine at modelnine.org
Tue Jul 29 17:06:46 EDT 2008


Also, just a couple of points:

Am 29.07.2008, 22:27 Uhr, schrieb Carl Banks <pavlovevidence at gmail.com>:
> 1. Any container type that returns a length that isn't exactly the
> number of elements in it is broken.

I agree, but how do you ever expect to return an infinite element count?  
The direction I took in that recipe was not returning some "magic" value  
but raising an OverflowError (for example, you could've also cropped the  
length at 2**31-1 as meaning anything equal to or larger). This is the  
thing that breaks your explicit test for non-emptyness using len(x) > 0,  
but it's also the only possible thing to do if you want to return the  
number of elements exactly where possible and inform the user when not  
(and OverflowError should make the point clear).

Anyway, that's why there is a separate member function which is explicitly  
documented to return a magic value in case of an infinite set (i.e., -1)  
and an exact element count otherwise, but using that (you could write  
x.len() != 0 for the type in question to test for non-emptiness) breaks  
polymorphism.

> 2. The need for __nonzero__ in this case depends on a limitation in
> the language.

True, but only for sets with are finite. For an infinite set, as I said  
above: what would you want __len__() to return? There is no proper  
interpretation of __len__() for an infinite set, even though the set is  
non-empty, except if you introduced the magic value infinity into Python  
(which I did as -1 for my "personal" length protocol).

> 3. On the other hand, I will concede that sometimes calculating len is
> a lot more expensive than determining emptiness, and at a basic level
> it's important to avoid these costs.  You have found a practical use
> case for __nonzero__.

This is just a somewhat additional point I was trying to make; the main  
argument are the two points you see above.

> However, I'd like to point out the contrasting example of numpy
> arrays.  For numpy arrays, "if x" fails (it raises an exception) but
> "if len(x)!=0" succeeds.
>
> The only sane advice for dealing with nonconformant classes like numpy
> arrays or your interger set is to be wary of nonconformances and don't
> expect polymorphism to work all the time.

The thing is: my integer set type IS conformant to the protocols of all  
other sequence types that Python offers directly, and as such can be used  
in any polymorphic function that expects a sequence type and doesn't test  
for the length (because of the obvious limitation that the length might  
not have a bound), but only for emptiness/non-emptiness. It's the numpy  
array that's non-conformant (at least from what you're saying here; I  
haven't used numpy yet, so I can't comment).

> So I guess I'll concede that in the occasional cases with
> nonconformant classes the "if x" might help increase polymorphism a
> little.
>
> (BTW: here's another little thing to think about: the "if x" is useful
> here only because there isn't an explicit way to test emptiness
> without len.)

The thing being, again, as others have already stated: __nonzero__() IS  
the explicit way to test non-emptiness of a container (type)! If I wanted  
to make things more verbose, I'd not use "if len(x)>0", but "if bool(x)"  
anyway, because "casting" to a boolean calls __nonzero__(). "if len(x)>0"  
solves a different problem (even though in set theory the two are  
logically similar), and might not apply to all container types because of  
the restrictions on the return value of __len__(), which will always exist.

--- Heiko.



More information about the Python-list mailing list