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