with keyword in python is used for exception handling when working with certain resources like files or database connections. These resources may need to have additional actions performed if an exception is raised.
For example, if there is an error reading from a file, we’d like to be certain the file gets closed before the program exits and raises the error. The
with statement is not limited to files or database connections, it can also be used with locks, sockets, sub-processes, telnet, and other types of connections.
In this article, we’ll take a deeper look at the
with keyword. We’ll look at how it works, when you should use it, and how you can create your own classes and functions that support
- Working knowledge of Python
- Python 3.8+
with Statement Works
Let’s start by taking a look at one of the most common uses for the ‘with’ statement: working with files.
File Handling without the
Let’s start with some simple code to write to a file.
file = open("sample1.txt", "w") file.write("Earthly is great!") file.close()
The code above:
- Opens a file called
sample1.txtin write mode
- Writes some text to the file
- Closes the file
As long as everything executes as expected, this code should work just fine, but a problem arises if at any point our program encounters and error and we don’t end up getting to the line where we close the file. If you don’t close a file properly, it can lead to data loss, resource leakage, or security vulnerabilities. In addition to that, it can also prevent other processes from being able to interact with the file in the future.
To avoid the above problems, you can use the
try-finally block as shown below:
file = open("sample2.txt", "w") try: file.write("Earthly is great!") finally: file.close()
The above code opens a file called
sample2.txt in a similar fashion as the previous example, but here we use the
write() method inside a
try block and the
close() method inside the
finally block. The
finally block ensures that the file closes properly if an exception occurs or not.
Learn more about exception handling in Python in this tutorial.
File Handling using the
In the previous example, you learned how to utilise exception handling to ensure a file closes in case of an error. But, you can do the same using the
with statement as shown below:
with open("sample3.txt", "w") as file: file.write("Earthly is great!")
In addition to helping you clean up resources after usage, the
with statement also allows you to include logic for acquiring resources or creating objects that will be used within the
with statement block.
For example, you can use a
try-finally block to acquire a lock as below:
import threading = threading.Lock() lock lock.acquire()try: # Critical section of code finally: lock.release()
However, the same can be written using
with statement in the following way:
import threading = threading.Lock() lock with lock: # Critical section of code # lock is automatically released when execution leaves this block
As you can see, the
with statement allows you to write this code more concisely and clearly. The
with statement automatically takes care of calling the
release() methods of the lock object, so you don’t have to include them in the
How to Create a Class That Supports the
You can create your own classes that support the
with statement. A class or a function that supports the
with statement is known as a Context Manager. The
open function is an example of a context manager.
A Python class that implements the methods below qualifies as a context manager:
__enter__(): This method is called when the
withstatement is executed, and it returns an object that will be bound to the variable specified in the
asclause of the
__exit__(): This method is called when the block of code inside the
withstatement has finished executing (regardless of whether an exception was raised or not). It is responsible for cleaning up any resources that the context manager might have acquired. The
__exit__()method can also handle exceptions that are raised within the
Once you implement the above two methods in your class, you can use the
with statement with the class.
When you call the
with statement, the context manager class invokes the
__enter__() method under the hood, and when you exit the scope of the
with statement, the class invokes the
Observe the code below to get a clearer picture:
class CustomFileWriter: def __init__(self, filename): self.filename = filename def __enter__(self): self.file = open(self.filename, 'w') return self.file def __exit__(self, exc_type, exc_value, traceback): self.file.close() # using the CustomFileWriter class for writing to a file with CustomFileWriter('sample4.txt') as file: file.write('Earthly is great!')
In the above code example, the
CustomFileWriter class is a context manager. It has three methods. The
__enter__() and the
- Python calls the
__init__()method (which is the constructor of the class) when you create an object from the class. In this method, you store the filename parameter as an instance variable of the object so that you can access it later.
- Python calls the
__enter__()method when it executes the
withstatement. The method is used to set up the context for the block of code that follows. In this case, the method opens the file with the given filename in write mode and returns a reference to the file object.
- Python calls the
__exit__()method when it finishes executing the block of code under the
withstatement. This method cleans up any resources (closing the file in this case) that the block accesses.
How to Create a Context Manager as a Function
In the previous section, you created a context manager class. However, you can also create a context manager function (like the
open() function) with the contexlib library:
from contextlib import contextmanager @contextmanager def custom_open(filename): try: = open(filename, "w") file_ptr yield file_ptr finally: file_ptr.close() with custom_open("sample5.txt") as file: file.write("Earthly is great!")
The above code defines a
custom_open() function, which is decorated with the
@contextmanager decorator. This allows you to define a context manager as a generator function, rather than defining a class with specific methods.
The generator function yields a file object when it is called. When the
with statement is executed and the generator function is called, it opens the file with the given filename in write mode and returns a reference to the file object.
When the code in the
with statement block has finished executing, Python executes the
finally block, which closes the file. This ensures that the file is always closed, even if an error occurs while writing to the file.
with statement in Python wraps the execution of a block of code with methods defined by a context manager. The
with statement provides a concise shorthand for a
try-finally block and ensures that resources are closed immediately after they are used. A context manager can be a function or a class that supports the
Through the example of file handling in Python, you learned:
- How the
- How you support the
withstatement in your own user-defined objects with the help of context managers.
- How the
withstatement helps you manage resources by closing the resources when an exception is raised.
The with statement is commonly used for reading from or writing to a file, but it can also be utilized for other purposes. You are welcome to further explore the capabilities of the
with statement and context managers.
While you’re here:
Earthly is the effortless CI/CD framework.
Develop CI/CD pipelines locally and run them anywhere!