Also, just a couple of points: Am 29.07.2008, 22:27 Uhr, schrieb Carl Banks <[EMAIL PROTECTED]>:
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. -- http://mail.python.org/mailman/listinfo/python-list