Python provides a statement that enables the developer to execute the concept of the
This can be broken up and learned using the analogy of the local variable inside the function. The local variable is created when a function is called automatically, and is ideally deleted when a function has completed execution.
In a case like this, we are releasing memory when we’re done with it. Similarly, in the case of context managers, the resource is locked or marked as ‘in use’ when the interpreter enters the context manager block. As soon as it’s exited, the lock is released.
In any programming language, the
If these resources are not released, they will lead to resource leakage and cause the system to either crash or slow down, which will be instrumental if a user has a teardown of resources and automatic setup. In Python, this can be realized with context managers, which facilitate the proper handling of resources.
If a block of code lifts an exception or has a complex algorithm with multiple return paths, it will become cumbersome to close the file in all the available places.
Generally, in different languages, when working with files, try-except-finally is used to confirm that the file resource is closed after usage even if there is an exception. However, Python gives an easy way to manage resources with context managers.
Context managers can be written using classes or functions (with decorators). When it gets evaluated, it should result in an object that performs context management.
When we create context managers using classes, users need to ensure that the class has the _enter()
and __exit()
methods.
The __enter()
method returns the resource that needs to be managed; while, the __exit_()
method does not return anything and performs the clean-up operations.
In this case, a ContextManager
object is created. This object is assigned to the variable after the
_init_()
_enter_()
with
block)_exit_()
(the parameters in this method are used to manage exceptions)Let’s apply the above concept to create a class that helps with file resource management. The File Manager class helps with opening a file, writing/reading contents, and then closing it.
Our _exit_
method accepts three arguments. They are useful by every _exit_
method, a part of the ContextManager
class. Let’s talk about what will happen under the hood:
with
statement will store the _exit_
method of a File class._enter_
method of a File class._enter_
method will open the file and return it.opened_file
..write()
.with
statement calls the stored _exit_
method._exit_
method closes the file.We did not discuss the type, value, or traceback arguments of an _exit_
method. If an exception occurs between the 4th and the 6th step, Python passes a type, value, and traceback of an exception to an _exit_
method. It allows an _exit_
method to decide how to close a file, and if any further steps are needed.
Let’s create a simple connection management system for a database. The number of database connections that can be opened at one time is also limited (just like the file descriptors). Therefore, the context managers are helpful in managing connections to the database, as there may be a chance that the programmer will forget to close the connection.
class ContextManager():def __init__(self):print('init method called')def __enter__(self):print('enter method called')return selfdef __exit__(self, exc_type, exc_value, exc_traceback):print('exit method called')with ContextManager() as manager:print('with statement block')
class FileManager():def __init__(self, filename, mode):self.filename = filenameself.mode = modeself.file = Nonedef __enter__(self):self.file = open(self.filename, self.mode)return self.filedef __exit__(self, exc_type, exc_value, exc_traceback):self.file.close()# loading a filewith FileManager('test.txt', 'w') as f:f.write('Test')print(f.closed)
class File(object):def __init__(self, file_name, method):self.file_obj = open(file_name, method)def __enter__(self):return self.file_objdef __exit__(self, type, value, traceback):print("Exception has been handled")self.file_obj.close()return Truewith File('demo.txt', 'w') as opened_file:opened_file.undefined_function()