[Python-Dev] why not "return StopIteration"?

Tim Peters tim.one@home.com
Fri, 22 Jun 2001 13:21:03 -0400


[Neil Schemenauer]
> Is "raise StopIteration" an abuse of exceptions?

I only care whether it works <wink>.  It certainly came as a surprise to me,
though, that I'm going to need to fiddle PEP 255 to explain that

    return

in a generator isn't really equivalent to

    raise StopIteration

(because a return in the try-part of a try/except should not trigger the
except-part if the generator is pumped again).

While a minor wart, it's a wart.  If this stands, I'm going to look into
changing gen_iternext() to determine whether eval_frame() finished by
raising StopIteration, and mark the iterator as done if so.  That is, force
"return" and "raise StopIteration" to act the same inside generators, and to
force "raise StopIteration" inside a generator to truly *mean* "I'm done" in
all cases.  This would also allow to avoid the proposed special-casing of
generators at the tail end of eval_frame() (yes, I'm anal <0.9 wink>:  since
it's a problem unique to generators, this simply should not be eval_frame's
problem to solve -- if generators create the problem, generators should pay
to solve it).

> Why can we not use "return StopIteration" to signal the end of an
> iterator?

Just explained why not yesterday, and you did two sentences later <wink>.

> ....
> This could be fixed in most causes by changing the tp_iternext
> protocol.  Something like:
>
>     int tp_iternext(PyObject *it, PyObject **item)
>
> were the return value is 1, 0, or -1.

Meaning 13, 42, and 666 respectively <wink>?  That is, one for "error", one
for "OK, and item is the next value", and one for "no error but no next
value either -- this iterator terminated normally"?  That could work.  At
one point during the development of the iterator PEP, Guido had some code
like that in the internals, on *top* of the exception business.  It was
clumsy then because redundant.

At the level of Python code, how would a user spell "end of iteration"?
Would iterators need to return a 2-two tuple in all non-exception cases
then, e.g. a (next_value, i_am_done_flag) pair?  Or would Python-level
iterators simply be unable to return StopIteration as a normal value?

> IOW, StopIteration would not have to come into the protocol if the
> object implemented tp_iternext.

All iterable objects in 2.2 implement tp_iternext, although sometimes it's a
Miranda tp_iternext (i.e., one created for an object that doesn't supply its
own), so that shouldn't be a worry.

All in all, I'm -0 on changing the exception approach -- it's worked very
well so far.