With Statement in Python

What is “with” Statement in Python

Anything that happens in programming consumes memory and disk space. When we create software we store it into the hard drive and run it in the memory. One problem that occurs is, if the programmer does not manage these resources properly then it causes issues like, the software will be slow, consume too many resources, etc.

One common scenario where this happens is when we try to work with files. Whenever a file is opened and an operation like writing text is performed, the data is stored in the temporary buffer.

Wait… What is a buffer?

Buffer is a place to store something temporarily. This is done when the input and output speed are different. A simple example is, when you watch any video online, the video service downloads the next few minutes of content to avoid any interruptions.

Buffer is a generic term and it is not specific to tech.

Coming back to the topic, when we open any file, our computer stores the file into a buffer so that we are able to perform operations on it without any issues.

Let’s say we open a file with python code, we perform operations on it, but we forget to close the file, then all the operations that were performed will be lost. Why? The reason is until the file is saved all the changes are made to the data stored in the buffer, and if we do not save the file then our computer will think that is unuseful data and will remove it. In simple words, our changes will be lost.

A similar thing can happen when there are exceptions and errors in the program.

To tackle these issues python provides us with two solutions:

  • Try…finally
  • With

Let’s take a look at them one by one

Try…Finally in Python

This is a simple approach, we “try” to do something (performing operations), and then we do some other thing “finally”.

It doesn’t matter if the code inside “try“ is successful or not, code inside “finally” will run after the try block.

This is a very common practice in python when we work with files. We open a file, do some operations like write to the file inside a “try” block and then close the file in the “finally” block.

With in Python

with statement in python aims to simplify the process of try…finally. It enables us to write cleaner and safer code. with can be considered as a simplified version for try…finally code. It handles the memory allocation and deallocation automatically.

Most commonly with is used with files

with open('hello.txt', mode='w') as myFile:
    myFile.write('I am inside with')

In the above code, we use with to open a file and perform operations on it. When the with block is executed it automatically closes the file even when an exception is raised.

If with is not used then it is the responsibility of the programmer to close the file. If the file is not closed then the performed operations will not be saved on the file.

But how does “with” know to close a file?

with statement can be used with all expressions that return an object which implements the context management protocol. Context managers allows us to allocate and release resources when we want to. This protocol contains two special functions:

  1. __enter__()

  2. __exit__()

As the name suggests, __enter()__ is called when the control enters with block, and __exit()__ is called when the control leaves with block.

When with statement executes, __enter__() is called on the context manager object to indicate the starting and when the flow leaves the context, __exit__() is called to indicate the end.

NOTE: with is shorter than try…finally but it is also less general which means “with” will work only with objects that support context management protocol.

Using “with” in user-defined objects

“with” has support with a lot of built-in methods like open()(used for opening files)but we can also use it in our custom methods. To use it in our custom methods we have to follow some conditions of with, let’s see how it can be done.

Wait… Why would I use “with” in my custom function?

“With” statement can help in many tasks that need to be performed at the start or end of a procedure.

E.g. In the case of file handling, you can define methods that can open and close the file for you. Or you are creating an app where you need to contact with a database, there you need to start a connection when the data transfer takes place and end the connection when the transfer is done.

“with” has a condition that it works with objects that support context management protocol, or it works with objects that have an __enter()__ and __exit()__ method.

We can make our own class with these methods and that will enable us to use “with”.

Here is an example of a simple class.

class MyContextManager:
    def __enter__(self):
        print("Entered the context")
        return "Entered!"
 
    def __exit__(self, *args, **kwargs):
        print("Leaving the context")
 
 
with MyContextManager() as hello:
    print(hello)

Output:

Entered the context
Entred!
Leaving the context

In the above code, we created a class MyContextManager and created two methods inside it named __enter__() and __exit__(). When we call this class using “with” we can see that the __enter__() runs first and then __exit__() runs.

In the code *args and **kwargs are used because __exit__() takes three arguments

  • execution_type
  • execution_value
  • traceback

These arguments should occur in this order.

  • execution_type is exception’s class.
  • execution_value is an exception instance which indicates the type of exception like, Zero Division Error, Floating Point Error
  • traceback is traceback object

When there are no exceptions raised, then all these args will return None, None, None.

Contextlib Library

contextlib library has a “contextmanager” decorator which provides an alternative and simple way to implement context management protocol. This reduces a lot of boilerplate code as it automatically provides __enter()__ and __exit()__ methods.

Let’s look at an example.

from contextlib import contextmanager
 
 
@contextmanager
def myContextManager():
    print("Entering...")
    yield "Hello There"
    print("Exiting...")
 
 
with myContextManager() as cm:
    print(cm)

Output:

Entering...
Hello There
Exiting...

The first thing you will notice is that there is no “class” used here. The decorator

“@contextmanager” allows us to create a function-based context manager.

There are two parts inside the function. The code before yield behaves like __enter()__ and the code after yield behaves like __exit()__

Yield is a keyword that is used like return, except the function where it is used will return a generator.

Conclusion

with is a useful keyword but it should be used with care.

Some advantages of with keyword are:

  • It makes resource management safer
  • Cleans up the code compared to try…finally
  • Helps in avoiding resource leaks

The only thing to keep in mind is that with only works with the objects that follow context management protocol.

Free Courses by top Scaler instructors
certificate icon
Certificates
Python Tutorial
This program includes modules that cover the basics to advance constructs of Python Tutorial. The highly interactive and curated modules are designed to help you become a master of this language.'
If you’re a learning enthusiast, this is for you.
Module Certificate
Criteria
Upon successful completion of all the modules in the hub, you will be eligible for a certificate.
You need to sign in, in the beginning, to track your progress and get your certificate.
rcbGet a Free personalized Career Roadmap from