Heh, I just played with this, and found a workaround. If I do something like this after creating the generator:
sys.g = g Then it wouldn't get closed when Python finishes, and the cleanup won't happen, which is what I want. This is still a bit ugly but now it's something I can do automatically for every generator-based context manager that I create, so it's not as bad as the previous workaround in my opinion. (I wouldn't create a new attribute for each context manager, but just have a list with a mangled name on `sys` that'll hold all of them.) On Sun, Nov 6, 2016 at 8:02 AM, Ram Rachum <r...@rachum.com> wrote: > Sorry, I was wrong at quoting the workaround I do, it's actually this: > > try: > yield > except GeneratorExit: > raise > except: > cleanup() > raise > else: > cleanup() > > This works, but it's ugly! And I basically need to do this to every > generator-based context manager that I want to be able to run just the > `__enter__` of without the `__exit__`. I wish there was a better solution > than including this in my code. > > On Sun, Nov 6, 2016 at 7:51 AM, Nick Coghlan <ncogh...@gmail.com> wrote: > >> On 6 November 2016 at 14:46, Ram Rachum <r...@rachum.com> wrote: >> > I worked around this problem by adding `except GeneratorExit: raise` in >> my >> > context manager, but that's an ugly solution. >> >> Adding `except GeneratorExit: raise` to a try statement with a finally >> clause won't prevent the finally clause from executing. >> >> Selective non-idempotent cleanup behaviour really isn't a good idea, >> so the language is fighting you for a reason here - the meaning of a >> "finally" clause is that the code it contains *will* get executed, and >> you have to try incredibly hard to keep that from happening since it's >> an implicit part of cleaning up unfinished generators, and we don't >> let you switch the nominal class of generator objects at runtime. >> Indeed, yield inside try/finally was prohibited for years prior to PEP >> 342, as the runtime previously couldn't guarantee that the finally >> clause would actually execute. >> >> If you *don't* want the code to execute unconditionally, then you need >> to be more explicit about when you *do* want it to execute with some >> combination of "except" and "else" clauses. For example: >> >> >>> @contextmanager >> ... def cm(): >> ... print("enter") >> ... try: >> ... yield >> ... except Exception: >> ... print("Normal exception, not GeneratorExit, >> KeyboardInterrupt or SystemExit") >> ... else: >> ... print("No exception") >> ... >> >>> cm().__enter__() >> enter >> >> Cheers, >> Nick. >> >> -- >> Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia >> > >
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/