Python Context Management Protocol consists of one keyword and two dunder methods: with
, __enter__()
and __exit__()
. It is proposed to replace the now legacy dunder __del__()
for its inconsistency on 202206062313#. The class or function that implements the protocol is called a context manager.
with
can be viewed as a syntactic sugar for try ... finally ...
and try ... except ...
(Python Exception Handling). The latter could be written as following:
f = TempClass.open(something)
try:
f.exec()
finally:
f.cleanup()
Versus the with
counterpart:
with f = TempClass.open(something):
f.exec()
Some would prefer using keyword as
to borrow instead of using the operator =
. The following shows the alternative way to write a with
clause:
with TempClass.open(something) as f:
f.exec()
We can see that either style reduces some code of line by eliminating the need to write out the finally
clause. It guarantees to always clean up the resource regardless if there is an exception. Additionally, the block immediately after the with
block will not be executed if exception is raised in the with
block. The block will be simply skipped.
Note: with
doesn’t accept comma-separated sequence of variables, we need to parenthesise the whole sequence instead.
For the class to be compatible to the with
clause and works as intended, two dunder methods must be implemented into the class: __enter__()
and __exit()__
. From the above example, the class TempClass
should render these methods:
class TempClass:
def __enter__(self):
return self # You can handle exception here
def __exit__(self, type, value, traceback):
self.cleanup() # You can handle exception here
If the __exit__()
return True
, the exception that happen within the with
clause will be swallowed, meaning continuing the execution, instead of crashing the whole program.
The method accepts three parameters (discounting self
, which points to the object itself): type
, value
and traceback
. type
is of type of the exception’s class, value
represents the instance of the exception and traceback
describes 202206101517#. You can utilise these parameters to your exception handling within the class method.
Instead of using classes, we can import the decorator contextmanager
and put it on the function for it to behave as a context manager similar to its class counterpart. This is shown as below, note that it uses 202206081813# keyword:
from contextlib import contextmanager
@contextmanager
def temp(something):
f = TempClass.open(something)
yield f
f.cleanup()
As always, you can handle exceptions inside a function context manager using try ... except ...
.
Reference
PEP 343 – The “with” Statement, Guido van Rossum and Nick Coghlan, 13-May-2005, https://peps.python.org/pep-0343/