Steven D'Aprano wrote:
On Sun, 27 Jul 2008 23:45:26 -0700, Carl Banks wrote:
I want something where "if x" will do but a simple explicit test won't.
Explicit tests aren't simple unless you know what type x is.
If you don't even know a duck-type for x, you have no business invoking any
methods on that object.
If you do know a duck-type for x, then you also know which explicit test to
perform.
Explicit tests are not necessarily simple for custom classes. Testing for
emptiness could be arbitrarily complex. That's why we have __nonzero__,
so you don't have to fill your code with complex expressions like (say)
if len(x.method()[x.attribute]) > -1
Instead you write it once, in the __nonzero__ method, and never need to
think about it again.
Okay, so you have this interesting object property that you often need to test
for, so you wrap the code for the test up in a method, because that way you only
need to write the complex formula once. I'm with you so far. But then you
decide to name the method "__nonzero__", instead of some nice descriptive name?
What's up with that?
This is the kind of code I would write:
class C:
def attribute_is_nonnegative(self):
return len(self.method()[self.attribute]) > -1
...
c = get_a_C()
if c.attribute_is_nonnegative():
...
Now suppose you were reading these last few lines and got to wondering if
get_a_C might ever return None.
The answer is obviously no. get_a_C must always return a C object or something
compatible. If not, it's a bug and an AttributeError will ensue. The code
tells you that. By giving the method a name the intent of the test is perfectly
documented.
In comparison, I gather you would write something like this:
class C:
def __nonzero__(self):
return len(self.method()[self.attribute]) > -1
...
c = get_a_C()
if c:
...
Again, the question is, can get_a_C return None? Well that's hard to say
really. It could be that "if c" is intended to test for None. Or it could be
intended to call C.__nonzero__. Or it could be cleverly intended to test
not-None and C.__nonzero__ at the same time. It may be impossible to discern
the writer's true intent.
Even if we find out that C.__nonzero__ is called, what was it that __nonzero__
did again? Did it test for the queue being non-empty? Did it test for the
queue being not-full? Did it test whether for the consumer thread is running?
Did it test for if there are any threads blocked on the queue? Better dig up
the class C documentation and find out, because there is no single obvious
interpretation of what is means for an object to evaluate to true.
"if x" is simple to type, but not so simple to read. "if x.namedPredicate()" is
harder to type, but easier to read. I prefer the latter because code is read
more often than it is written.
regards,
Anders
--
http://mail.python.org/mailman/listinfo/python-list