Context manager on method call from class

Joseph L. Casale jcasale at activenetwerx.com
Thu Mar 15 14:17:31 EDT 2018


I have a class which implements a context manager, its __init__
has a signature and the __enter__ returns an instance of the
class.

Along with several methods which implement functionality on
the instance, I have one method which itself must open a context
manager against a call on an instance attribute. This context manager
does not return an instance of itself, it merely opens a context.

I am not thrilled about is the implementation I have used and I
am wondering if there is a better way. It's been a long time since
I have worked in Python and I am probably overlooking something
obvious. Syntactically I achieve what I want in use, but it looks awkward
in its implementation. How can I clean up the first class and decorator
to implement the functionality on a method in the Foo class?

class MethodContextManager:
    def __init__(self, obj, key, value):
        self.obj = obj
        self.key = key
        self.value = value

    def __enter__(self):
        self.obj.some_method(key, value)

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.obj.another_method()


def method_context_manager(func):
    def wrapper(self, key, value):
        return MethodContextManager(self.instance, key, value)
    return wrapper


class Foo:
    def __init__(self, bar):
        self.bar = bar
        self.instance = None

    def __enter__(self):
        self.instance = SomeFunc(this.bar)

        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        # Cleanup...

    @method_context_manager
    def baz(self, key, value):
        pass


with Foo(bar) as foo:
    foo.other_call()
    with foo.baz(42, "a"):
        foo.other_call()
        with foo.baz(420, None):
            foo.other_call()
            foo.other_call()
        foo.other_call()
    foo.other_call()


More information about the Python-list mailing list