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 -- http://mail.python.org/mailman/listinfo/python-list