How should a context manager created inside another context manager be handled in Python?
Example: suppose you have class A
that acts as a context manager, and class B
that also acts as a context manager. But class B
instances will have to instantiate and use an instance of class A
. I've gone through PEP 343 and this is the solution I thought of:
class A(object): def __enter__(self): # Acquire some resources here return self def __exit__(seplf, exception_type, exception, traceback): # Release the resources and clean up pass class B(object): def __init__(self): self.a = A() def __enter__(self): # Acquire some resources, but also need to "start" our instance of A self.a.__enter__() return self def __exit__(self, exception_type, exception, traceback): # Release the resources, and make our instance of A clean up as well self.a.__exit__(exception_type, exception, traceback)
Is this the correct approach? Or am I missing some gotchas?
Yes, the context manager will be available outside the with statement and that is not implementation or version dependent. with statements do not create a new execution scope.
Context managers can be written using classes or functions(with decorators). Creating a Context Manager: When creating context managers using classes, user need to ensure that the class has the methods: __enter__() and __exit__().
contextmanager() uses ContextDecorator so the context managers it creates can be used as decorators as well as in with statements.
Context managers allow you to allocate and release resources precisely when you want to. The most widely used example of context managers is the with statement. Suppose you have two related operations which you'd like to execute as a pair, with a block of code in between.
If you can use the @contextlib.contextmanager
decorator your life gets a lot easier:
import contextlib @contextlib.contextmanager def internal_cm(): try: print "Entering internal_cm" yield None print "Exiting cleanly from internal_cm" finally: print "Finally internal_cm" @contextlib.contextmanager def external_cm(): with internal_cm() as c: try: print "In external_cm_f", c yield [c] print "Exiting cleanly from external_cm_f", c finally: print "Finally external_cm_f", c if "__main__" == __name__: with external_cm(): print "Location A" print with external_cm(): print "Location B" raise Exception("Some exception occurs!!")
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