Context Manager Syntax
As we all know, the proper way to release the resource is by closing the resource after its use. And the most common practice followed to structure the close function is by using Exception Handling. Let’s look into the below code.
def main(): try : file = open ( 'sample.txt' , 'r' ) data = file .read() print (data) finally : file .close() main() |
The finally clause ensures that the file will be closed irrespective of any situation. But this process results in code repetition. So, how you achieve the same using Context Manager without the boilerplate setup. Let’s go through the below sections one by one:
- The with statement
- The enter and exit method
- Exception Handling
The with statement
with statement, the python built in function can be used as a context manager.
with open (‘filename’, ’r’) as file : data = file .read() |
This code performs the same functionality of what we developed using exception handling. Here the with statement is expected to return an object with two magic methods: __enter__ and __exit__. The result returned from __enter__ method is assigned to the variable mentioned after the `as` keyword.
It handles if an exception is raised within the wrapped code and most importantly the statement ensures that the resource is released. So, the programmers need not perform the close operation. Here is the full code.
def main(): with open ( 'sample.txt' , 'r' ) as file : data = file .read() print (data) main() |
The enter and exit method
The __enter__ method returns an object, and then the returned value is assigned to the variable mentioned after the `as` keyword. Other than self argument it takes no other arguments.
On the other hand, the __exit__ method takes 3 positional arguments other than self argument. By default, these three arguments are none and are populated with information when the wrapped code raises an exception.
The below code explains the workflow of the Context Manager. Keep a note of the inside attribute and How the attribute value changes in different scenarios. Upon entering the context manager, the attribute value is set to true and on exit, its value is set to false. Once the block of code within the with statement completes execution the __exit__ method gets invoked.
class ContextCheck( object ): def __init__( self ): self .inside = False def __enter__( self ): self .inside = True return self def __exit__( self , exc_type, exc_instance, traceback): self .inside = False cntCheck = ContextCheck() print (cntCheck.inside) with cntCheck: print (cntCheck.inside) print (cntCheck.inside) |
Output
False True False
Exception Handling
How the exception is handled using the Context Manager?
Using the __exit__ method, the context manager handles exceptions that are raised by the wrapped code. __exit__ method has 3 positional arguments:
- Type of the Exception
- An instance of the Exception
- Traceback option
By default, all three values are None. When an __exit__ method receives an exception, the method can handle the exception in 2 different ways:
- Re-raise the exception
- Suppress the exception
Re-raise the exception
The __exit__ method can re-raise the exception by having a return statement that returns False. Let’s see the below code:
class BubbleExc( object ): def __enter__( self ): return self def __exit__( self , ex_type, ex_instance, traceback): if ex_instance: print ( 'Exception: % s.' % ex_instance) return False with BubbleExc(): 1 / 0 |
Output
Exception: division by zero. Traceback (most recent call last): File "C:\Users\Sonu George\Documents\Python\Context Managers\bubbleExc.py", line 11, in 1/0 ZeroDivisionError: division by zero
Suppress the exception
The __exit__ method can suppress the exception by returning true. See the below example for detailed understanding.
class SuppressExc( object ): def __enter__( self ): return self def __exit__( self , ex_type, ex_instance, traceback): if ex_instance: print ( 'Suppressing exception: % s.' % ex_instance) return True with SuppressExc(): 1 / 0 |
Output>
Suppressing exception: division by zero.
Reusable piece of python functionality for wrapping arbitrary blocks of code : Python Context Managers
Context Managers are the tools for wrapping around arbitrary (free-form) blocks of code. One of the primary reasons to use a context manager is resource cleanliness. Context Manager ensures that the process performs steadily upon entering and on exit, it releases the resource. Even when the wrapped code raises an exception, the context manager guarantees the exit. So, without any procrastination, lets dive and acquire the new mantra for resource cleanliness without the code repetition.
Note: Knowledge about Decorators and Generators is appreciated