[Python-ideas] Generator-based context managers can't skip __exit__

Nick Coghlan ncoghlan at gmail.com
Sun Nov 6 01:53:52 EST 2016


On 6 November 2016 at 16:07, Ram Rachum <ram at rachum.com> wrote:
> 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.

The interpreter goes to significant lengths to make sure that finally
clauses get executed prior to or during interpreter shutdown, and any
means you find by which they don't get executed is considered a bug
(not always a fixable bug, but a bug nonetheless). If you rely on
those bugs and limitations to get your program to perform the way you
want it to you're going to run into problems later when upgrading to
new CPython versions, or trying out different interpreter
implementations.

There's still something seriously odd going in relation to your
overall resource management architecture if "cleanup, maybe, unless I
decide to tell you not to" is a behaviour you regularly need. Cleanup
functions in a garbage collected environment should be idempotent, so
it doesn't matter if you redundantly call them again later.

However, if you *do* need that pattern regularly, then the pattern
itself can be encapsulated in a context manager:

    class callback_unless_exit:
        def __init__(self, callback):
            self.callback = callback
        def __enter__(self):
            return self
        def __exit__(self, exc_type, exc_value, exc_tb):
            if issubclass(exc_type, GeneratorExit):
                return
            self.callback()

and then do:

    with callback_unless_exit(cleanup):
        yield

in the context managers where you want that behaviour.

Regards,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-ideas mailing list