Context Manager in Python

Last Updated : 30 May, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

In any programming language, the usage of resources like file operations or database connections is very common. But these resources are limited in supply. Therefore, the main problem lies in making sure to release these resources after usage. If they are not released then it will lead to resource leakage and may cause the system to either slow down or crash.
Python’s context managers provide a neat way to automatically set up and clean up resources, ensuring they’re properly managed even if errors occur.

Using the with Statement for File Handling

The simplest way to manage a file resource is using the with keyword:

Python
with open("test.txt") as f:
    data = f.read()

This ensures the file is automatically closed once the block is exited, even if an error occurs.

What Happens Without Proper Closing?

If files aren’t closed, you can run out of available file descriptors. For example:

Python
file_descriptors = []
for x in range(100000):
    file_descriptors.append(open('test.txt', 'w'))

This will raise:

Traceback (most recent call last):
File "context.py", line 3, in
OSError: [Errno 24] Too many open files: 'test.txt'

Because too many files remain open, exhausting system resource

Why Use Context Managers?

In complex programs, especially those with multiple exit points or exceptions, manually closing files or connections everywhere is error-prone. Context managers automate this cleanup using the with keyword.

Creating a Custom Context Manager Class

A class-based context manager needs two methods:

  • __enter__(): sets up the resource and returns it.
  • __exit__(): cleans up the resource (e.g., closes a file).

Example:

Python
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:

init method called
enter method called
with statement block
exit method called

The above sequence shows how Python initializes the object, enters the context, runs the block, and then exits while cleaning up.

File Management Using Context Manager

Let's apply the above concept to create a class that helps in file resource management. The FileManager class helps in opening a file, writing/reading contents, and then closing it. 

Python
class FileManager:
    def __init__(self, filename, mode):
        self.filename = filename
        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()

with FileManager('test.txt', 'w') as f:
    f.write('Test')

print(f.closed)

Output:

True

Explanation:

  • __enter__() opens the file and returns it.
  • Inside the with block, you can use the file object.
  • __exit__() ensures the file is closed automatically.
  • print(f.closed) confirms the file is closed.

Database Connection Management with Context Manager

Let's create a simple database connection management system. The number of database connections that can be opened at a time is also limited(just like file descriptors). Therefore context managers are helpful in managing connections to the database as there could be chances that the programmer may forget to close the connection. 

Python
from pymongo import MongoClient

class MongoDBConnectionManager:
    def __init__(self, hostname, port):
        self.hostname = hostname
        self.port = port
        self.connection = None

    def __enter__(self):
        self.connection = MongoClient(self.hostname, self.port)
        return self.connection

    def __exit__(self, exc_type, exc_value, exc_traceback):
        self.connection.close()

with MongoDBConnectionManager('localhost', 27017) as mongo:
    collection = mongo.SampleDb.test
    data = collection.find_one({'_id': 1})
    print(data.get('name'))

Explanation:

  • __enter__() opens the MongoDB connection.
  • mongo inside the with block is the client object.
  • You can perform database operations safely.
  • __exit__() closes the connection automatically.

Next Article
Article Tags :
Practice Tags :

Similar Reads