[Python-ideas] Function to return first(or last) true value from list

Andrew Barnert abarnert at yahoo.com
Fri Feb 21 06:58:16 CET 2014


On Feb 20, 2014, at 16:59, Ethan Furman <ethan at stoneleaf.us> wrote:

> On 02/20/2014 02:38 PM, אלעזר wrote:
>> 2014-02-21 0:00 GMT+02:00 Steven D'Aprano wrote:
>>> 
>>> Why is it dangerous, and what kind of bug?
>>> 
>>> If you're talking about the fact that next(it) can raise StopIteration,
>>> I think you are exaggerating the danger. Firstly, quite often you don't
>>> mind if it raises StopIteration, since that's what you would have done
>>> anyway. Secondly, I don't see why raising StopIteration is so much more
>>> dangerous than (say) IndexError or KeyError.
>> I had this bug just the other day. I did not plan for the empty case, since it was obvious that the empty case is a bug,
>> so I relied on the exception being raised in this case. But I did not get the exception since it was caught in a
>> completely unrelated for loop. It took me a while to figure out what's going on, and it would've taken even more for
>> someone else, not familiar with my assumption or with the whole StopIteration thing (which I believe is the common
>> case). An IndexError or a KeyError would have been great in such a case.

I don't think most people unfamiliar with StopIteration are calling next manually. Maybe there's a brief period where you've learned enough about how the iteration protocol works to be calling iter and next but not enough to know about StopIteration--but that period ends the first time you have to debug your code, and from then on, you know.

> I think the basic problem is that a few exceptions are intended for the Python interpreter itself, but that's easy to forget, particularly since that list is so small:
> 
>  StopIteration
>  ...
>  um, any others?

GeneratorExit, and in a different way KeyboardInterrupt and SystemExit. Presumably that's why none of these four inherit from StandardError and everything else does.

And of course IndexError in the special case where you're using the legacy iteration protocol.

Meanwhile, attribute access (and/or the default __getattribute__ implementation) handles both KeyError and AttributeError at various levels. Operators and augmented assignments use attribute access, and also directly handle AttributeError and NotImplementedError. If you count builtins that get direct data-model support as part of the interpreter, they do similar things to operators. The import system handles various IOError subclasses, and I think it may also internally raise and handle ImportError in some cases. Maybe the interpreter handles EOFError as well somewhere, I'm not sure. Probably more I didn't think of off the top of my head.

So, the class of "dangerous" exceptions  where you have to know that the interpreter might treat them specially includes most of the most common exceptions.

> Consequently we need to remind ourselves that we are not likely to see that exception under normal circumstances; and vice-a-versa, we need to remind ourselves to catch it if we are playing with next().

This is the point. You have to know which exceptions to deal with in different kinds of code. If you're playing with next, you need to know about StopIteration. If you're playing with generator.send, you need to know about GeneratorExit. If you're creating custom number-like classes or __getattr__-based proxies, you need to know exactly when AttributeError is handled and what it means. Maybe some of this info isn't easy to find until the first time you try to do it (without a good tutorial) and run into bugs, but once you know what to look for the docs are pretty clear.



More information about the Python-ideas mailing list