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

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Thu Jul 31 19:08:46 EDT 2008


On Thu, 31 Jul 2008 22:01:48 +0100, Matthew Woodcraft wrote:

> Steven D'Aprano wrote:
>>On Wed, 30 Jul 2008 20:55:03 +0100, Matthew Woodcraft wrote:
> 
>>> On the other hand, iterators provide a clear example of problems with
>>> "if x": __nonzero__ for iterators (in general) returns True even if
>>> they are 'empty'.
> 
>> How do you propose telling whether an iterator is empty? That's a
>> generic problem with any sort of lazy function. You don't know if it
>> has finished unless you try grabbing data from it.
> 
> Of course.
> 
> The point is that if you tell people that "if x" is the standard way to
> check for emptiness, and also support a general principle along the
> lines of "write your function using the interfaces you expect, and call
> it using the object you have", you should expect to end up with bugs of
> this sort.

I'm not sure that an occasional performance hit justifies calling it a 
bug. I suppose you might come up with a scenario or two where it really 
is a problem, but then I'm also free to imagine scenarios where calling 
len(obj) takes a massive performance hit, or has irreversible side 
effects.


>>> For example, this function (which attempts to avoid making an
>>> expensive call when not necessary) is buggy, but easy to write if
>>> you've been taught that "if x" will work with any kind of object.
>>>
>>> def frob(widgets, power):
>>>     if widgets:
>>>         frobber = Frobber(power) # expensive call
>>>         for widget in widgets:
>>>             frobber.frob(widget)

But note that the code still does the right thing even if widgets is 
empty. The only problem is that it needlessly calls Frobber. Frankly, 
that would have to be *really* expensive before I would even bother using 
the more complicated code. This is a good example of premature 
optimization.

 
>> AFAIK there's no great solution to this problem. It's inherent in the
>> way lazy functions work. Certainly you can't replace the call to "if
>> widgets" with "if len(widgets)", because iterators don't have a length.
> 
> I'm not a fan of len() for testing emptiness. But it would have been
> better in this case, because it would have converted a hard-to-find
> performance bug into an obvious exception.

At the cost of wrongly raising a exception for perfectly good arguments, 
namely non-empty iterators.



-- 
Steven



More information about the Python-list mailing list