Context Managers in Python
Context managers help you manage resources in Python in a safe and automatic way. They make sure that setup and cleanup actions happen correctly, even if errors occur. They are commonly used with files, network connections, and database operations.
What Is a Context Manager?
A context manager controls a block of code using two steps: entering and exiting. Python runs special logic when the block starts and when it ends. This ensures resources are opened and closed properly without manual work.
The with Statement
The with keyword creates a safe environment to work with resources.
When the block finishes, Python automatically cleans up.
This avoids bugs and makes code easier to read.
with open("data.txt", "r") as file:
content = file.read()
print(content)
Here, Python automatically closes the file after the block finishes, even if an error happens inside the block.
Why Do We Use Context Managers?
They help prevent resource leaks such as files left open. They reduce repetitive boilerplate code like closing connections manually. They keep programs cleaner, safer, and more organized.
Creating a Custom Context Manager (Using a Class)
You can build your own context manager using two special methods:
__enter__() runs when the block starts,
and __exit__() runs when the block ends.
class DemoManager:
def __enter__(self):
print("Entering block")
return "Resource Ready"
def __exit__(self, exc_type, exc_value, traceback):
print("Exiting block")
with DemoManager() as msg:
print(msg)
This example shows how a context manager prepares something before use and finishes tasks after use automatically.
Context Managers Using contextlib
Python’s contextlib module lets you create context managers
using a cleaner function-based style.
This is shorter and easier when you only need simple logic.
from contextlib import contextmanager
@contextmanager
def simple_manager():
print("Start")
yield
print("End")
with simple_manager():
print("Inside block")
The yield keyword marks the point where the controlled block runs.
Everything before yield is setup, and everything after is cleanup.
Real-World Example: Temporary Change in Directory
Context managers are useful for controlling temporary states. Below is an example that changes the working directory only inside the block and automatically restores it afterward.
import os
from contextlib import contextmanager
@contextmanager
def change_directory(path):
original = os.getcwd()
os.chdir(path)
try:
yield
finally:
os.chdir(original)
with change_directory("/tmp"):
print("Now inside /tmp")
This keeps directory changes controlled and prevents errors that might occur when switching back manually.
📝 Practice Exercises
Exercise 1
Create a custom context manager that prints “Begin” when entering and “Finish” when leaving.
Exercise 2
Use contextlib to create a context manager that times how long a block runs.
Exercise 3
Create a file-handling context manager that automatically opens and closes a file.
Exercise 4
Create a context manager that temporarily changes a list and restores it afterward.
✅ Practice Answers
Answer 1
class CM:
def __enter__(self):
print("Begin")
def __exit__(self, a, b, c):
print("Finish")
with CM():
print("Inside")
Answer 2
import time
from contextlib import contextmanager
@contextmanager
def timer():
start = time.time()
yield
end = time.time()
print("Time:", end - start)
with timer():
x = sum(range(100000))
Answer 3
class FileManager:
def __init__(self, name):
self.name = name
def __enter__(self):
self.file = open(self.name, "w")
return self.file
def __exit__(self, a, b, c):
self.file.close()
with FileManager("sample.txt") as f:
f.write("Hello")
Answer 4
from contextlib import contextmanager
@contextmanager
def temp_list_edit(lst):
backup = lst.copy()
yield lst
lst[:] = backup
items = [1, 2, 3]
with temp_list_edit(items) as temp:
temp.append(99)
print(items)