Skip to content

Context Managers & The 'with' Statement

Managing resources—like files, network sockets, or database connections—is a critical part of programming. If you open a file but forget to close it, your program “leaks” resources, which can eventually lead to a crash.

Python’s Context Managers provide a guaranteed way to “clean up” resources, even if your code crashes halfway through.


The with statement simplifies resource management by ensuring that “cleanup” code is always executed.

f = open("data.txt", "w")
f.write("Hello")
# If the write fails, f is never closed!
f.close()

To make your own class a context manager, you must implement two methods:

  • Called at the start of the with block.
  • The value it returns is what gets assigned to the variable after the as keyword.

2. __exit__(self, exc_type, exc_value, traceback)

Section titled “2. __exit__(self, exc_type, exc_value, traceback)”
  • Called at the end of the with block.
  • It receives information about any error that occurred inside the block.
  • If it returns True, the error is suppressed (the program doesn’t crash).
database_mock.py
class Database:
def __enter__(self):
print("Connecting to DB...")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Closing connection...")
if exc_type:
print(f"An error occurred: {exc_val}")
return True # Suppress the error
with Database() as db:
raise RuntimeError("Lost connection!")
print("The program is still running!")

Writing a whole class for a simple context manager is overkill. Python provides a decorator in the contextlib module that lets you use a Generator.

simple_timer.py
from contextlib import contextmanager
import time
@contextmanager
def timer():
start = time.time()
try:
yield # Everything before this is __enter__
finally:
# Everything after this is __exit__
end = time.time()
print(f"Elapsed: {end - start:.4f}s")
with timer():
time.sleep(1)

A with statement is essentially a try...finally block wrapped in a cleaner syntax.

When you use with, Python guarantees that the __exit__ method (the “cleanup” phase) will run, regardless of whether the code inside the block:

  • Finishes successfully.
  • Returns from a function.
  • Raises an exception.
  • Stops the program (mostly).

ResourceWhy use a Context Manager?
FilesEnsures the file is closed and the buffer is flushed.
LocksEnsures a “Mutex” or “Lock” is released so other threads can work.
DB ConnectionsEnsures the connection is returned to the pool.
Mocks/TestingTemporary overrides of system settings or environment variables.