In this stage of the course, we dove into one of Python’s most elegant features: context managers.
Everyone has used with open(filename)
— but few understand what really happens under the hood. This part of the course uncovered that mystery.
Step 1 — What Is a Context Manager?
A context manager is any object that defines two special methods:
def __enter__(self):
# Setup logic (open file, acquire resource)
return something
def __exit__(self, exc_type, exc_value, traceback):
# Cleanup logic (close file, release resource)
This is what the with
statement uses behind the scenes.
Step 2 — Building One From Scratch
We built a context manager that times a code block:
import time
class Timer:
def __enter__(self):
self.start = time.time()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.end = time.time()
print(f"Elapsed: {self.end - self.start:.2f} seconds")
Used like this:
with Timer():
# Some expensive operation
result = sum(i * i for i in range(10**6))
Step 3 — Handling Exceptions Gracefully
The __exit__
method can control whether exceptions are suppressed:
def __exit__(self, exc_type, exc_val, traceback):
if exc_type:
print("An error occurred:", exc_val)
return True # Suppress exception
Step 4 — Using contextlib
To avoid writing boilerplate classes, Python includes contextlib
:
from contextlib import contextmanager
@contextmanager
def timer():
start = time.time()
yield
end = time.time()
print(f"Elapsed: {end - start:.2f} seconds")
Same behavior, less code.
Lessons Learned
- Context managers are not just for files — they’re for any resource that needs setup and teardown
- You can use them to wrap logic cleanly, especially when debugging, timing, or handling transactions
- Writing your own makes you appreciate how Python balances simplicity with power
Next up: we’ll explore exception handling patterns in depth — and how Python’s control flow and call stack really behave.