Python Context Manager with Statement

Context Manager in Python

In Python, the Context Manager is an object designed to guarantee that resources are utilized correctly within a code block, automatically releasing those resources afterward. This functionality enhances both efficiency and code cleanliness. It allows users to manage various resources through the enter and exit methods.

In this guide, we will explore the concept of "Context Manager" in Python and examine its utility in handling resources, file handles, and database connections.

Managing Resources

Resource management is a crucial aspect of the Context Manager. It facilitates more efficient utilization of resources. Users often engage with resources such as file operations or database connections, which are prevalent across various programming languages.

However, all these resources come with constraints. Consequently, the primary challenge lies in ensuring that these resources are freed up once they are no longer needed.

Failure to release resources can result in resource leakage, potentially leading to either a system slowdown or a crash. If the environment is configured to automatically deallocate resources, it can prove to be extremely beneficial. In Python, this can be accomplished through the use of context managers, which ensure efficient management of resources. The most common method for executing file operations is by employing the "with" statement in Python.

Python Example to Manage Resources

Consider an example to illustrate the process of resource management in Python.

Example

with open("text_file.txt") as file:

    data = file.read()

Consider an illustration of file management. Upon opening a file, the file descriptors are utilized, representing a finite resource. Consequently, the process is restricted to opening a certain maximum number of files simultaneously.

Another Example to demonstrate Manage Resources

Let us consider an additional example to illustrate the management of resources in Python.

Example

file_descriptors = []

for Y in range(10000):

    file_descriptors.append( open ('test_file.txt', 'w'))

Output:

Output

OSError Traceback (most recent call last)

in

1 file_descriptors = []

2 for Y in range(10000):

----> 3 file_descriptors.append( open ('test_file.txt', 'w'))

OSError: [Errno 24] Too many open files: 'test_file.txt'

Explanation

The previous example illustrates a scenario involving file descriptor leakage. An error message indicated, "Too many open files." This situation arose due to an excessive number of open files that remain unclosed. It is possible that users neglected to close the files that were opened.

How to Manage Resources using Context Manager?

Closing a file in every location can be challenging if the program's block encounters an exception or involves a complicated algorithm with multiple return routes.

Frequently, developers utilize "try-except-finally" constructs in various programming languages when handling files to ensure that file resources are released after use, regardless of whether an exception occurs. However, in Python, they can leverage "Context Manager" for resource management. The "with" keyword can be employed for this purpose. Upon evaluation, it produces an object capable of context management. Context managers can be implemented through classes or functions utilizing decorators.

How to Create a Context Manager?

Upon creating a context manager, it is essential for the class to include the following methods: enter and exit.

  • The enter method is responsible for returning the resource that needs to be managed.
  • The exit method does not return any value; instead, it is responsible for executing the necessary clean-up tasks.

Consider an example to gain a clearer understanding:

Initially, we will develop a straightforward class called "context_manager" to grasp the fundamental framework for constructing a context manager through the use of the class method.

Python Example to Create a Context Manager

As an illustration, we will show how to construct a context manager in Python.

Example

class context_manager():

    def __init__(self):

        print ("The 'init' method is called")

    def __enter__(self):

        print ("The 'enter' method is called")

        return self

    def __exit__(self, exc_type, exc_value, exc_traceback):

        print ("The 'exit' method is called")

with context_manager() as manager:

    print ("The 'with' statement is a block")

Output

Output

The 'init' method is called

The 'enter' method is called

The 'with' statement is a block

The 'exit' method is called

Explanation

In the above code, we have created the "context_manager" object. That is assigned to the variable after the "as" keyword, that is, manager. After running the program, the following methods got executed in the sequence:

  • int
  • enter
  • Body of statement, which is the code inside the "with" statement block.
  • exit, In this method, the parameters are used for managing the exceptions.
  • File Management by using Context Manager

We will now implement the aforementioned concept to develop a class that facilitates file resource management. The "file_manager" class will be responsible for opening a file, reading or writing data, and subsequently closing the file.

Example

class file_manager():

    def __init__(self, file_name, mode):

        self.filename = file_name

        self.mode = mode

        self.file = None

    def __enter__(self):

        self.file = open(self.filename, self.mode)

        return self.file

    def __exit__(self, exc_type, exc_value, exc_traceback):

        self.file.close()

# At last, load the file

with file_manager('test_file.txt', 'w') as file:

    file.write(	)

print (file.closed)

Output:

Performing File Management using Context Manager and "with" Statement?

After the user executes the "with" statement block, the operations will get executed in the following sequence:

  • A "filemanager" object will be created with "textfile.txt" as the file name, and "w" (write) as the mode when the init method will be executed.
  • The enter method will open the "textfile.txt" in write mode and return the "filemanager" object to the variable "file".
  • The text "Example" will be written into the file.
  • The exit method will take care of closing the file after exiting the "with" statement block, which is a teardown operation.
  • When the "print (file.closed)" statement runs, the users will get the output "True" as the "file_manager" would have already closed the file, which otherwise would need to be explicitly done.
  • How to Manage the Database Connection using Context Manager?

We will now demonstrate the process of developing a basic database connection management system. Similar to file descriptors, there exists a limitation on the number of concurrent database connections. Consequently, we utilize a context manager, which proves beneficial in overseeing the database connections, especially since the user may neglect to close the connection.

Install pymongo

In order to handle the database connection via the content manager, the user must initially install the "pymongo" library by executing the following command:

Example

!pip3 instal pymongo

Python Example to Manage the Database Connectio using Context Manager

Let us consider an example to illustrate how to handle the database connection utilizing context management in Python.

Example

from pymongo import MongoClient as moc

class mongo_db_connection_manager():

    def __init__(self, host_name, port = '27017'):

        self.hostname = host_name

        self.port = port

        self.connection = None

    def __enter__(self):

        self.connection = moc(self.hostname, self.port)

        return self

    def __exit__(self, exc_type, exc_value, exc_traceback):

        self.connection.close()

# Now, connect with a localhost

with mongo_db_connection_manager('localhost', 27017) as mongo:

    collection_1 = mongo.connection.SampleDb.test

    data_1 = collection_1.find({'_id': 142})

    print (data_1.get(name))

Output:

Explanation:

In the above code, after executing the "with" statement block, the following operations will happen in the sequence.

  • The "mongodbconnectionmanager" object will be created with "localhost" as the "hostname" and the port is equal to "27017" when the init method is executed.
  • The enter method will open the "mongodb" connection, and it will return the "mongodbconnection_manager" object to the variable "mongo".
  • The "SampleDB" database will access the "test" connection, and the document with the "_id = 147" will be retrieved. It will print the name field of the document.
  • The exit method will take care of closing the file after exiting the "with" statement block, which is a teardown operation.
  • Conclusion

In this instructional guide, we have explored the concept of Context Manager in Python, the process of creating a Context Manager, and its benefits for Resource Management, File handling, and Database connection management.

Python Context Manager FAQs

1. What is a Context Manager in Python?

A Context Manager in Python is beneficial for handling resources, file descriptors, and database connections. It is primarily utilized in conjunction with the with statement.

2. Why do we use a Context Manager?

We use a context manager in Python:

  • To ensure resources are properly closed
  • To avoid memory leaks
  • To make code cleaner and more readable
  • 3. What is the most common example of a Context Manager?

Let’s examine a typical illustration of a Context manager that ensures a file is closed automatically.

Example

with open("file.txt", "r") as f:

    data = f.read()

4. Where are Context Managers used in real life?

The Context Managers are used in various places in real life, such as:

  • File handling (open)
  • Database connections
  • Threading locks
  • Network connections (sockets, requests)
  • Temporary changes in environment/config
  • 5. Can we create our own Context Manager?

Indeed, it is possible to develop a custom Context Manager. Let us examine an example to understand the process involved.

Example

class MyContext:

    def __enter__(self):

        print("Entered the context")

        return self

    def __exit__(self, exc_type, exc_value, traceback):

        print("Exited the context")

with MyContext():

    print("Inside block")

6. How does a Context Manager work internally?

The Context Manager operates through two functions: the enter function and the exit function.

  • enter: The enter function is executed upon entering the block.
  • exit: The exit function is executed upon exiting the block.
  • 7. How is a Context Manager different from try/finally?

try/finally: It manually manages setup & cleanup

Context Manager: The Context Manager enhances clarity, improves readability, and reduces the likelihood of mistakes.

Example:

Example

# Create the file first for demonstration

with open("file.txt", "w") as f:

    f.write("This is a test file.\n")

    f.write("This is the second line.")

# Using try/finally

f = open("file.txt", "r")

try:

    data = f.read()

    print("Data from try/finally:", data)

finally:

    f.close()

# Using context manager

with open("file.txt", "r") as f:

    data = f.read()

    print("Data from context manager:", data)

Output:

Output

Data from try/finally: This is a test file.

This is the second line.

Data from context manager: This is a test file.

This is the second line.

Input Required

This code uses input(). Please provide values below: