So here's an interesting issue I just discovered while experimenting with async generators. It caught me by surprise, anyway. Maybe this was already obvious to everyone else. But I wanted to get some more perspectives.
Starting axiom: async functions / async generators need to be prepared for the case where they get garbage collected before being run to completion, because, well... this is a thing that can happen. Currently, the way garbage collection is handled is that their __del__ method calls their .close() method, which does something like: class GeneratorType: ... def close(self): try: self.throw(GeneratorExit) except GeneratorExit, StopIteration: return # it worked, all is good except: raise # double-fault, propagate else: raise RuntimeError("generator ignored GeneratorExit") (see PEP 342). So far, so obvious -- an async function that gets a GeneratorExit has to propagate that exception immediately. This is a regular method, not an async method, because it Dismaying conclusion: inside an async function / async generator, finally: blocks must never yield (and neither can __aexit__ callbacks), because they might be invoked during garbage collection. For async functions this is... arguably a problem but not super urgent, because async functions rarely get garbage collected without being run to completion. For async generators it's a much bigger problem. There's some more discussion, and a first sketch at conventions we might want to use for handling this, here: https://github.com/dabeaz/curio/issues/70 -n -- Nathaniel J. Smith -- https://vorpus.org _______________________________________________ Async-sig mailing list Async-sig@python.org https://mail.python.org/mailman/listinfo/async-sig Code of Conduct: https://www.python.org/psf/codeofconduct/