Python Context Managers Explained – __enter__, __exit__, and contextlib
Introduction – Why Use Context Managers?
In Python, you often need to acquire and release resources safely. Think of:
- Opening and closing files
- Acquiring and releasing locks
- Managing database connections
- Timing or logging blocks of code
Context managers provide a clean, readable way to manage such resources automatically—using the with statement.
In this guide, you’ll learn:
- What context managers are and how they work
- How the
withstatement simplifies resource management - How to create custom context managers using classes or decorators
- Real-world use cases and best practices
What Is a Context Manager?
A context manager is a Python object that defines how to set up and clean up a resource.
It must implement two methods:
__enter__(self) → Called at the start of the `with` block
__exit__(self, exc_type, exc_val, exc_tb) → Called at the end, even on errors
Built-in Context Manager Example – File Handling
with open("sample.txt", "w") as f:
f.write("Hello, context managers!")
Automatically closes the file after writing—even if an exception occurs.
Equivalent to:
f = open("sample.txt", "w")
try:
f.write("Hello")
finally:
f.close()
Custom Context Manager Using a Class
class ManagedFile:
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_val, exc_tb):
self.file.close()
with ManagedFile("log.txt") as f:
f.write("Logging entry")
Resource is acquired on __enter__() and released on __exit__().
🧙♂️ Context Managers with contextlib
from contextlib import contextmanager
@contextmanager
def managed_file(name):
f = open(name, "w")
try:
yield f
finally:
f.close()
with managed_file("output.txt") as file:
file.write("Written with contextlib")
Use @contextmanager for simpler and cleaner code when using generators.
Multiple Context Managers in One Line
with open("in.txt") as infile, open("out.txt", "w") as outfile:
data = infile.read()
outfile.write(data)
Use comma-separated context managers to manage multiple resources.
Exception Handling in Context Managers
class SafeBlock:
def __enter__(self):
print("Entering block")
def __exit__(self, exc_type, exc_value, traceback):
print("Exiting block")
if exc_type:
print(f"Error: {exc_value}")
return True # suppresses exception
with SafeBlock():
raise ValueError("Oops") # Handled silently
Real-World Use Cases
| Use Case | Description |
|---|---|
| File I/O | Open/read/write files |
| Thread locks | Acquire/release threading/multiprocessing locks |
| Database connections | Open/close cursor or session |
| Timers/Profilers | Measure time around a code block |
| Temporary directory/files | Create and clean up temp resources |
️ Example – Context Manager Timer
import time
from contextlib import contextmanager
@contextmanager
def timer():
start = time.time()
yield
end = time.time()
print(f"Elapsed time: {end - start:.2f}s")
with timer():
time.sleep(1.5)
Output:
Elapsed time: 1.50s
Best Practices
| Do This | Avoid This |
|---|---|
Use with for resources like files, locks | Manually handling open/close |
Use contextlib for simple wrappers | Creating classes when a function will do |
Always clean up in __exit__ or finally | Ignoring cleanup logic |
Handle exceptions in __exit__() | Letting exceptions crash without cleanup |
Summary – Recap & Next Steps
Context managers in Python offer a clean and Pythonic way to manage resources. They reduce boilerplate and ensure your code stays safe, concise, and readable.
Key Takeaways:
- Use
withstatements to manage setup and teardown - Custom context managers implement
__enter__and__exit__ - Use
contextlibfor decorator-based managers - Great for files, locks, connections, timers, and logging
Real-World Relevance:
Used in file systems, database clients, thread management, testing, and resource cleanup frameworks.
FAQ – Python Context Managers
What does a context manager do?
It handles setup and teardown logic automatically via __enter__ and __exit__.
Can I use multiple with statements?
Yes. Use a comma-separated list or nested blocks.
Is __exit__ called on exception?
Yes. It runs even if an exception occurs—great for cleanup.
When should I use contextlib?
Use it when your context logic fits well into a generator (setup, yield, cleanup).
What if I forget to close a file?
You risk a resource leak. Always prefer the with statement to handle it safely.
Share Now :
