Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Context manager inside a class instance

Tags:

python

I would like to create a context manager class that's specific for an instance of another class. I can do it by calling a method that creates a class, but I'm not sure this is the best, nicest way:

class MyClass(object):
    def __init__(self):
        self.level = 0
        self.Nest = self.create_context_manager()
    def inclev(self):
        self.level += 1
    def declev(self):
        self.level -= 1

    def create_context_manager(self):
        self2 = self
        class Nest(object):
            def __init__(self):
                pass
            def __enter__(self):
                self2.inclev()
            def __exit__(self, exc_type, exc_value, traceback):
                self2.declev()
        return Nest

# Manually increase/decrease level
my_instance = MyClass()
print(my_instance.level)
my_instance.inclev()
print(my_instance.level)
my_instance.inclev()
print(my_instance.level)
my_instance.declev()
print(my_instance.level)
my_instance.declev()
print(my_instance.level)

# Use instance-specific context manager
other_instance = MyClass()
print(other_instance.level)
with other_instance.Nest():
    print(other_instance.level)
    with other_instance.Nest():
        print(other_instance.level)
    print(other_instance.level)
print(other_instance.level)
like image 695
Jellby Avatar asked Jan 28 '16 16:01

Jellby


People also ask

When would you use a context manager?

A context manager usually takes care of setting up some resource, e.g. opening a connection, and automatically handles the clean up when we are done with it. Probably, the most common use case is opening a file. The code above will open the file and will keep it open until we are out of the with statement.

What is required to make a class A context manager?

Creating a Context Manager: When creating context managers using classes, user need to ensure that the class has the methods: __enter__() and __exit__(). The __enter__() returns the resource that needs to be managed and the __exit__() does not return anything but performs the cleanup operations.

What is a context manager in programming?

Context managers are used to set up and tear down temporary contexts, establish and resolve custom settings, and acquire and release resources. The open() function for opening files is one of the most familiar examples of a context manager.


1 Answers

Why do you need a nested class? Just have the main object implement the context management protocol directly:

class MyClass(object):
    def __init__(self):
        self.level = 0
    def inclev(self):
        self.level += 1
    def declev(self):
        self.level -= 1

    __enter__ = inclev  # For __enter__, just alias inclev, no need for wrapper
    def __exit__(self, exc_type, exc_value, traceback):
        self.declev()

Then just use it with:

with other_instance:
    print(other_instance.level)
    with other_instance:
        print(other_instance.level)
    print(other_instance.level)

If you really need the context manager protocol as a constructed thing named Nest, you can still simplify a bit with builtins from contextlib:

from contextlib import contextmanager

class MyClass(object):
    def __init__(self):
        self.level = 0
    def inclev(self):
        self.level += 1
    def declev(self):
        self.level -= 1

    @contextmanager
    def Nest(self):
        self.inclev()
        try:
            yield
        finally:
            self.declev()
like image 58
ShadowRanger Avatar answered Oct 05 '22 08:10

ShadowRanger