__exit__ must accept 3 arguments: type, value, traceback¶
A contextmanager class is any class that implements the __enter__ and __exit__ methods according to the Python Language Reference’s context management protocol. Implementing the context management protocol enables you to use the with statement with instances of the class. The with statement is used to ensure that setup and teardown operations are always executed before and after a given block of code. It is functionally equivalent to try...finally blocks, except that with statements are more concise.
For example, the following block of code using a with statement…
with EXPRESSION:
BLOCK
… is equivalent to the following block of code using try and finally statements.
EXPRESSION.__enter__()
try:
BLOCK
finally:
EXPRESSION.__exit__(exception_type, exception_value, traceback)
In order for __exit__ to work properly it must have exactly three arguments: exception_type, exception_value, and traceback. The formal argument names in the method definition do not need to correspond directly to these names, but they must appear in this order. If any exceptions occur while attempting to execute the block of code nested after the with statement, Python will pass information about the exception into the __exit__ method. You can then modify the definition of __exit__ to gracefully handle each type of exception.
Anti-pattern¶
The __exit__ method defined in the Rectangle class below does not conform to Python’s context management protocol. The method is supposed to take four arguments: self, exception type, exception value, and traceback. Because the method signature does not match what Python expects, __exit__ is never called even though it should have been, because the method divide_by_zero creates a ZeroDivisionError exception.
class Rectangle:
def __init__(self, width, height):