Writing Context Manager
Knowing is not enough; we must apply. Willing is not enough; we must do.
– Johann Wolfgang von Goethe
Implementing a Context Manager as a Class
A sample method that writes to a file using Context Manager. Here is the full code.
class FileClass( object ): def __init__( self , f_name, func): self .f_obj = open (f_name, func) def __enter__( self ): return self .f_obj def __exit__( self , type , value, traceback): self .f_obj.close() with FileClass( 'sample.txt' , 'w' ) as f_open: f_open.write( 'Congratulations, Good Work !' ) |
Output
Congratulations, Good Work!
Closing a page using Context Manager
Here the page.close() will be called after completion of reading the page (upon exit from the with block).
from contextlib import closing from urllib.request import urlopen for ln in page: print (ln) |
Output
Using a Context Manager as a function Decorator and Generator
With the python contexlib module, you can implement context manager as decorator and the yield statement within the method gives the flexibility to use it as a generator. To understand this program, you should have prior knowledge about decorators and generators.
from contextlib import contextmanager @contextmanager def open_file(name): try : print ( 'File Open' ) f = open (name, 'r' ) yield f finally : print ( 'Close Operation' ) f.close() def main(): with open_file( 'sample.txt' ) as f: data = f.read() print (data) main() |
Here @contextmanager wraps the open_file method. When the function open_file gets invoked, the __enter__method of the context manager executes and pass the control to open_file method where the file opens and yield the file reference to callable with open_file('sample.txt') as f
and the execution halts before executing the finally block.
Once the code within the with statement is executed, it passes the control back to the open_file and the execution begins from where it is halted. In this case, the finally block executes and closes the file. Upon completion of execution, the __exit__ method is called and it handles any exception that is raised by the wrapped code.
Handling exception by checking instance of an Exception Class
In this case, we will check whether an exception is an instance of an exception class. Below we will create a subclass ‘TypeErrorSubclass’, which is derived from the ‘TypeError’ exception class, and using the raise statement we will raise the ‘TypeErrorSubclass’ exception. Here is the full code.
class TypeErrorSubClass(TypeError): pass class ExceptionClass( object ): def __enter__( self ): return self def __exit__( self , ex_type, ex_instance, traceback): # Return True if there is no exception if not ex_type: return True # Return True if execution type is # equal or a subclass of TypeError if issubclass (ex_type, TypeError): print ( 'Handling TypeError: % s' % ex_instance) return True return False with ExceptionClass(): raise TypeErrorSubClass( 'Type Error' ) |
Output
Handling ValueError: Type Error
The __exit__ method checks if the exception raised is an instance of ‘TypeError’ class using issubclass(ex_type, TypeError)
, and if it’s an instance then suppress the exception by returning True.
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