Let's say we've got an class 'A' that acts as a context manager in it's own right, so it implements the
def __enter__()
def __exit__()
interface. It's valid for client code to make 'A' objects directly using a with statement.
Now, we've also got another class 'B' that encapsulates other functionality, as well makes use of an 'A' object.
If we'd like to have 'B' act as a context manager as well, what's the right way of managing it's 'A' instance?
Should the implementation of __enter__ and __exit__ on 'B' call __enter__ and __exit__ (respectively) on it's A-object instance? Or is there a better way?
To give a concrete example (this is not what I'm using in my application, it's just the first non-abstract example that came to mind) consider two classes
DatabaseConnectionDatabaseConnectionPoolIt's valid to use a single DatabaseConnection on it's own, thus DatabaseConnection implements the context-manager interface.
DatabaseConnectionPool makes use of several DatabaseConnections as well as other bits and bobs. Using DatabaseConnectionPool (i.e. "with") should do the set up and tear-down on it's DatabaseConnection instances (along with whatever else it might want to do)
Update: I've written some test code which I was hoping would give the following output:
Enter invoked on Outer Enter invoked on Inner Within outer context... do_foo invoked! Still using outer... Exit invoked on inner Exit invoked on outer Done using outer
but I got the following:
Enter invoked on Outer Enter invoked on Inner Exit invoked on inner Within outer context... do_foo invoked! Still using outer... Exit invoked on outer Done using outer
Code:
class Inner(object):
def __enter__(self):
print "Enter invoked on Inner"
return self
def __exit__(self, typ, val, tb):
print "Exit invoked on inner"
def do_foo(self):
print "do_foo invoked!"
class Outer(object):
def __init__(self):
self._inner = Inner()
def __enter__(self):
print "Enter invoked on Outer"
with self._inner as ctx:
return self
def __exit__(self, typ, val, tb):
print "Exit invoked on outer"
with Outer() as outer:
print "Within outer context..."
outer._inner.do_foo()
print "Still using outer..."
print "Done using outer"
Any ideas on how to make this work?
FWIW, I had the same design consideration, and ended up writing exit and enter functions in my 'child' classes, and only have the 'parent' class be a context manager.
(If I've understood your question correctly, which would be 'how can I elegantly also have all the classes that I've used in a context manager class close correctly when I've closed the parent context manager)
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