On Sun, Mar 29, 2009 at 10:45 PM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
The problem of how to handle GeneratorExit doesn't seem to have any entirely satisfactory solution.
On the one hand, the inlining principle requires that we never re-raise it if the subgenerator turns it into a StopIteration (or GeneratorReturn).
On the other hand, not re-raising it means that a broken generator can easily result from innocuously combining two things that are individually legitimate.
I think we just have to accept this, and state that refactoring only preserves semantics as long as the code block being factored out does not catch GeneratorExit without re-raising it. Then we're free to always re-raise GeneratorExit and prevent broken generators from occurring.
I'm inclined to think this situation is a symptom that the idea of being able to catch GeneratorExit at all is flawed. If generator finalization were implemented by means of a forced return, or something equally uncatchable, instead of an exception, we wouldn't have so much of a problem.
Earlier I said that I thought GeneratorExit was best regarded as an implementation detail of generators. I'd like to strengthen that statement and say that it should be considered a detail of the *present* implementation of generators, subject to change in future or alternate Pythons.
Related to that, I'm starting to come back to my original instinct that GeneratorExit should not be thrown into the subiterator at all. Rather, it should be taken as an indication that the delegating generator is being finalized, and the subiterator's close() method called if it has one. Then there's never any question about whether to re-raise it -- we should always do so.
This sounds fine -- though somehow I have a feeling nobody will really care either way, and when it causees a problem, it's going to cost an afternoon of debugging regardless. So do what's easiest to implement, we can always fix it later. BTW, I'd really like it if you (and others interested in PEP 380) read Dave Beazley's excellent coroutines tutorial (http://dabeaz.com/coroutines/), and commented on how yield-from can make his example code easier to write or faster. The tutorial comes with ample warnings about its mind-bending nature but I found it excellently written and very clear on the three different use cases for yield: iteration, receiving messages, and "traps" (cooperative multitasking). I cannot plug this enough. (Thanks Jeremy Hylton for mentioning it to me.) -- --Guido van Rossum (home page: http://www.python.org/~guido/)