Photo by Luca Bravo on UnsplashContext Managers & with statementWith statement behind the scenes!!Rachit TayalBlockedUnblockFollowFollowingMay 21Why Context Managers?Opening a file for writing and closing it after performing the desired writes are some common operations during file handling.
When a file is opened, it is assigned a file descriptor by the OS.
Consider the below snippet:f = open('some_file.
close()If due to some exception, file is not closed then we will be leaking a file descriptor which we should avoid as there is a limit to number of files a process can open at one time.
Therefore, to avoid our program to leak a file descriptor, we need to put the method calls under try/catch block as below:f = open('some_file.
txt', 'w')try: f.
')except: print ("Something went wrong.
close()We can mirror the above implementation using the with statement with fewer lines of code.
Also there is tendency of forgetting to close the files which we can overcome using the with statement.
txt', 'w') f.
')It is most widely used example of context manager.
The with statement allows us to write a cleaner, more readable code by abstracting the resource handling logic.
Using with can help avoid bugs or leaks by ensuring that the resources are freed when no longer required.
We can say that the most common use of context manager is to manage resources.
Context manger allows us to allocate, deallocate resources specifically when we want to.
Let’s see how we can implement our own Context Manager.
This should give us a fair understanding to what exactly is going behind the scenes.
What is a Context Manager?To the very least context manager are just classes that specify the __enter()__ and __exit()__ methods.
As per PEP 343:A context manager is an object that is notified when a context (a block of code) starts and ends.
You commonly use one with the with statement.
It takes care of the notifying.
To define a context manager, all we need is to define two special methods to our class: __enter()__ & __exit()__Let’ first create a dummy context manager to understand the flow.
class ContextManager(): def __init__(self): print('init method called') def __enter__(self): print('enter method called') return self def __exit__(self, exc_type, exc_value, exc_traceback): print('exit method called')with ContextManager() as manager: print('with statement block')Output of the above snippet will be:init method calledenter method calledwith statement blockexit method calledThe above ContextManager object determines the flow of execution.
As seen from the output above, __enter__ method is called first, followed by code block inside the with statement, followed by the call to __exit__ method.
Now let’s look at a more practical example.
Let’s define our own File class which resembles the implementation of open() context manager.
class File: def __init__(self, name): self.
name = name def __enter__(self): self.
file = open(self.
name, 'w') return self.
file def __exit__(self, exc_type, exc_val, exc_tb): if self.
close()Our above definedFile class follows context manager specification and can support the with statement, just like the open() method.
>>> with File('some_file.
txt') as f:.
')Python will call __enter()__ when execution enters the context of the with statement and it’s time to acquire the resource.
When execution leaves the context again, Python calls __exit()__ to free the resource.
ConclusionsSpecify the __enter__ & __exit__ context manager methods to support your class to be used with with statement.
with statement allows efficient and cleaner management of the resources by abstracting the try/catch exception handling inside context managers.