Is "raise StopIteration" an abuse of exceptions? Why can we not use "return StopIteration" to signal the end of an iterator? I've done a bit of hacking and the idea seems to work. On possible problem is that the StopIteration object in the builtin module could cause some confusing behavior. For example the code: for obj in __builtin__.__dict__.values(): print obj would not work as expected. 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. IOW, StopIteration would not have to come into the protocol if the object implemented tp_iternext. Neil
[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.
On Fri, Jun 22, 2001 at 01:21:03PM -0400, Tim Peters wrote:
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).
I don't get this. Currently, (unless Just checked in his patch) generators work in exactly that way: the compiler compiles 'return' into 'raise StopIteration' if it encounters it inside a generator, and into a regular return otherwise. Why would you ask for the patch Just provided, and then change it back ? -- Thomas Wouters <thomas@xs4all.net> Hi! I'm a .signature virus! copy me into your .signature file to help me spread!
[Thomas Wouters]
I don't get this. Currently, (unless Just checked in his patch) generators work in exactly that way: the compiler compiles 'return' into 'raise StopIteration' if it encounters it inside a generator, and into a regular return otherwise.
Yes. The part about analyzing the return value inside gen_iternext() would be the only change from the status quo.
Why would you ask for the patch Just provided, and then change it back ?
I wouldn't. I asked *you* for a patch (which I haven't yet applied, but will) in a different area, but Just's patch was his own initiative. I hesitated on that one for reasons beyond just lack of time to get to it, and I'm still reluctant to accept it. My msg sketched an alternative to that patch. Note that Just has also (very recently) sketched another alternative, but on the Iterators list instead. just-isn't-in-need-of-defense-because-he-isn't-being-abused<wink>-ly y'rs - tim
participants (3)
-
Neil Schemenauer -
Thomas Wouters -
Tim Peters