Object-Oriented Context Managers¶
Here is a direct implementation of the interface. SNR not great.
In [2]:
class ClassicalContext():
def __init__(self, name):
self.name = name
def __enter__(self):
print('Enter ' + self.name)
return ('Content of ' + self.name)
def __exit__(self, exc_type, exc_value, traceback):
print('Exit ' + self.name)
with catch_and_print():
with ClassicalContext('a') as a:
print('In context:', a)
raise ValueError('Something fishy here.')
# Notice a is torn down before exception reaches you!
Enter a In context: Content of a Exit a EXCEPTION: Something fishy here.
Function Decorator: contextlib.contextmanager
¶
I prefer to use this notation whereever possible.
It allows me to write construction and destruction of my context as one linear function.
There should be one yield
, which returns a value (file, socket, etc...) to the context creator.
Everything after the yield
is executed on context exit.
In [3]:
import contextlib
@contextlib.contextmanager
def simple_context_without_exception_handling(name):
print('Enter ' + name)
yield('Content of ' + name)
print('Exit ' + name)
Used as before:
In [4]:
with simple_context_without_exception_handling('b') as b:
print('In context:', b)
Enter b In context: Content of b Exit b
But, as you might have guessed by my naming: Exception handling is missing:
In [5]:
with catch_and_print():
# But shows unwanted behaviour when exceptions come into play:
with simple_context_without_exception_handling('c') as c:
print('In context:', c)
raise ValueError('Something fishy here.')
# Notice missing exit of c!
Enter c In context: Content of c EXCEPTION: Something fishy here.
Here is a full example with proper exception handing:
In [6]:
@contextlib.contextmanager
def better_context(name):
print('Enter ' + name)
try:
yield('Content of ' + name)
finally:
print('Exit ' + name)
In [7]:
with catch_and_print():
with better_context('d') as d:
print('In context:', d)
raise ValueError('Something fishy here.')
Enter d In context: Content of d Exit d EXCEPTION: Something fishy here.
So while (imho) easier to read, there is a danger of forgetting to handle exceptions.