[Python-ideas] sentinel_exception argument to `iter`

Steven D'Aprano steve at pearwood.info
Fri Feb 7 09:28:54 CET 2014


On Thu, Feb 06, 2014 at 09:36:19PM -0500, Terry Reedy wrote:
> On 2/6/2014 7:10 PM, Ram Rachum wrote:
> 
> >`iter` has a very cool `sentinel` argument. I suggest an additional
> >argument `sentinel_exception`; when it's supplied, instead of waiting
> >for a sentinel value, we wait for a sentinel exception to be raised, and
> >then the iteration is finished.
> >
> >This'll be useful to construct things like this:
> >
> >     my_iterator = iter(my_deque.popleft, IndexError)
> >
> >What do you think?
> 
> I think this would be a great idea if simplified to reuse the current 
> parameter.

That would be a backwards-incompatible change, for exactly the reason 
you give below:

> It can work in Python because exceptions are objects like 
> anything else and can be passed as arguments.

Right. And there is a big difference between *returning* an exception 
and *raising* an exception, which is why a new parameter (or a new 
function) is required. A function might legitimately return exception 
objects for some reason:

exceptions_to_be_tested = iter(
    [IndexError(msg), ValueError, StopIteration, TypeError]
    )

def func():
    # pre- or post-processing might happen
    return next(it)


for exception in iter(func, StopIteration):
    # assume the exceptions are caught elsewhere
    raise exception


With the current behaviour, that will raise IndexError and ValueError, 
then stop. With the suggested change in behaviour, it will raise all 
four exceptions.

We cannot assume that an exception is never a legitimate return result 
from the callable. "Iterate until this exception is raised" and "iterate 
until this value is returned" are very different things and it is folly 
to treat them as the same.



[...]
> I consider the threat to backward compatibility, because of the added 
> test for exceptions, theoretical rather than actual. It is very rare to 
> write a function that returns an exception, 

Rare or not, I've done it, it's allowed by the language, and it is 
inappropriate to conflate returning a class or instance with raising an 
exception.

It doesn't matter whether it is rare. It is rare to write:

iter(func, ({}, {}))

nevertheless it would be poor design to have iter treat tuples of 
exactly two dicts as a special case.

Exceptions are first-class values like strings, ints, and tuples 
containing exactly two dicts. They should be treated exactly the same as 
any other first-class value.



-- 
Steven


More information about the Python-ideas mailing list