On Sun, Oct 31, 2010 at 1:00 AM, Guido van Rossum guido@python.org wrote:
What has this got to do with GeneratorExit and g.close()? I propose to modify g.close() to keep throwing GeneratorExit until the generator stops yielding values, and then capture the return value from StopIteration if that is what was raised. The beauty is then that the PEP 380 expansion can stop special-casing GeneratorExit: it just treats it as every other exception. And stddev() above works! (If you worry about infinite loops: you can get those anyway, by putting "while: True" in an "except GeneratorExit" block. I don't see much reason to worry more in this case.)
I'm back to liking your general idea, but wanting to use a new method and exception for the task to keep the two sets of semantics orthogonal :)
If we add a finish() method that corresponds to your stop() function, and a GeneratorReturn exception as a peer to GeneratorExit:
class GeneratorReturn(BaseException): pass
def finish(self): if g.gi_frame is None: return self._result # (or raise RuntimeError) try: next(self) while True: self.throw(GeneratorReturn) except StopIteration as ex: return ex.value
Then your node counter iterator (nice example, btw) would simply look like:
def count_nodes(node): if not node: return 0 count = 0 count += yield from count_nodes(node.left) try: yield node except GeneratorReturn: return count count += 1 # Only count nodes when next is called in response count += yield from count_nodes(node.right) return count Cheers, Nick.