Greg Ewing wrote:
Jacob Holm wrote:
will also remove some behavior that could have been useful, such as the ability to suppress the GeneratorExit if you know what you are doing.
I'm not convinced there are any use cases for suppressing GeneratorExit in the first place. Can you provide an example that couldn't be easily done some other way?
I don't have any real use cases, just a few examples of things you can do in #2 that become a bit uglier in #3 or #4. This: def inner(): try: for i in xrange(10): yield i except GeneratorExit: return i return "all" def outer(): val = yield from inner() print val return val Does not behave like you would expect because the "return i" is swallowed by the call to inner.close() (or is it?) and the "print val" and "return val" statements are skipped due to the reraised GeneratorExit. To get the a value out of the generator being closed you need to raise and catch your own exception: class Return(Exception): pass def inner(): try: for i in xrange(10): yield i except GeneratorExit: raise Return(i) return "all" def outer(): try: val = yield from inner() except Return as r: val = r.args[0] print val return val This is certainly doable, but ugly compared to the version using return. Here is an idea that would help this a little bit. We could change close to return the value (if any) returned by the generator, and then attach that value to the reraised GeneratorExit in the yield-from expansion. That would allow the example to be rewritten as: def inner(): try: for i in xrange(10): yield i except GeneratorExit: return i return "all" def outer(): try: val = yield from inner() except GeneratorExit as e: val = e.value print val return val Which I think is much nicer. - Jacob