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)
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.
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.
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.
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With