Hi Nick Nick Coghlan wrote:
Jacob Holm wrote:
If I understand Nick correctly, he would like to drop the "except GeneratorExit: raise" part, and possibly change BaseException to Exception. I don't like the idea of just dropping the "except GeneratorExit: raise", as that brings us back in the situation where shared subiterators are less useful. If we also change BaseException to Exception, the only difference is that it will no longer be possible to throw exceptions like SystemExit and KeyboardInterrupt that don't inherit from Exception to a subiterator.
Note that as of 2.6, GeneratorExit doesn't inherit from Exception either - it now inherits directly from BaseException, just like the other two terminal exceptions:
I know this.
All I'm saying is that if GeneratorExit doesn't get passed down then neither should SystemExit nor KeyboardInterrupt, while if the latter two *do* get passed down, then so should GeneratorExit.
I also know this, and I disagree. You are saying that because they have the thing in commen that they do *not* inherit from Exception we should treat them the same. This is like saying that anything that is not a shade of green should be treated as red, completely ignoring the possibility of other colors. I like to see GeneratorExit handled as a special case by yield-from, because: 1. It already has a special meaning in generators as the exception raised in the generator when close is called. 2. It *enables* certain uses of yield-from that would require much more more work to handle otherwise. I am thinking of the ability to have multiple generators yield from the same iterator. Being able to close one generator without closing the shared iterator seems like a good thing. 3. While the GeneratorExit is not propagated directly, its expected effect of finalizing the subiterator *is*. At least in CPython, and assuming the subiterator does its finalization in a __del__ method, and that the generator holds the only reference. If the subiterator is actually a generator, it will even look like the GeneratorExit was propagated, due to the PEP 342 definition of close. I don't like the idea of only throwing exceptions that inherit from Exception to the subiterator, because it makes the following two generators behave differently when thrown a non-Exception exception. def generatorA(): try: x = yield except BaseException, e: print type(e) raise def generatorB(): return (yield from generatorA()) The PEP is clearly intended to make them act identically. Quoting from the PEP: "When the iterator is another generator, the effect is the same as if the body of the subgenerator were inlined at the point of the yield from expression". Treating only GeneratorExit special allows them to behave exactly the same (in CPython). If you only propagate exceptions that inherit from Exception, you would have to write something like: def generatorC(): g = generatorA() while 1: try: return (yield from g) except Exception: # This exception comes from g, so just reraise raise except BaseException, e: yield g.throw(e) # this exception was not propagated by yield-from, do it manually to get the same effect. I don't mind that the expansion as written in the PEP becomes very slightly more complicated, as long as it makes the code using it simpler to reason about. - Jacob