Python Context Management Protocol

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/

Links to this page
#python #resource #exception