coding screen terminal python

Photo by Karub ‎ on Pexels


We’ve all been through the emotional rollercoaster of writing a script, walking away to grab a coffee, and coming back to a server screaming about “Too many open files” because we forgot a pesky .close() statement. It’s the coding equivalent of leaving the refrigerator door wide open—inefficient, messy, and entirely avoidable. Luckily, Python’s context managers and the trusty with statement are here to save us from ourselves by automating the cleanup crew.

Welcome back to the Old Lane 17 workshop, where we like our code clean, our coffee black, and our terminal windows uncluttered by enterprise bloat. Today, we are looking at Python context managers: what they are, why you should use them, and how to write your own custom ones without losing your sanity.

The Problem: The “I’ll Close It Later” Fallacy

Let’s look at how most of us start our Python journeys (or how we write code when we’re running on three hours of sleep and pure spite).

python
# The "Hope and a Prayer" approach
f = open("important_secrets.txt", "w")
f.write("We love clean code at Old Lane 17.")
# Oops! An exception happened here.
raise ValueError("Cat walked across the keyboard.")
f.close()  # This never runs. Sad trombone.

When an exception gets thrown between opening the file and closing it, your program crashes, and the file resource remains locked in limbo until the garbage collector eventually wakes up from a nap and cleans it up. That is bad practice, and deep down, you know it.

The Solution: Enter the with Statement

Python native types—like files, database connections, and locks—support the context manager protocol out of the box. Wrap them in a with statement, and Python guarantees that the cleanup method will be called, even if the code inside explodes spectacularly.

python
# The "Adult in the Room" approach
with open("important_secrets.txt", "w") as f:
    f.write("We love clean code at Old Lane 17.")
    # Even if an error happens here...
    
# ...Python automatically slams the door shut on this file. 
# Resource leak avoided. High fives all around.

The Real-World Gotcha: Swallowing Exceptions by Accident

Here is a classic trap when people try to write their own custom context managers using the contextlib module. They try to handle exceptions gracefully, but accidentally turn into a vacuum cleaner that swallows every bug in sight.

python
from contextlib import contextmanager

@contextmanager
def terrible_database_transaction():
    print("-> Opening connection")
    try:
        yield
    except Exception as e:
        print(f"Caught an error! {e}")
        # GOTCHA: By not re-raising the exception, Python thinks 
        # everything is totally fine and suppresses the crash!
    finally:
        print("-> Closing connection")

# Usage:
with terrible_database_transaction():
    raise KeyError("Missing config key!")
    
print("Program keeps running like nothing happened... until it totally breaks later.")

If an exception occurs inside the with block and your custom context manager catches it without a raise or returning True intentionally, you are masking bugs. Your future self will spend hours debugging why a failure was silently ignored.

Writing a Clean Custom Context Manager

If you want to time operations or manage custom resources without hiding bugs, keep your try...finally logic tight and let exceptions bubble up naturally.

python
import time
from contextlib import contextmanager

@contextmanager
def time_it(task_name):
    start_time = time.time()
    try:
        # Give control back to the 'with' block
        yield
    finally:
        # This ALWAYS runs, whether the code succeeded or crashed
        elapsed = time.time() - start_time
        print(f"[Done] '{task_name}' took {elapsed:.4f} seconds.")

# Usage:
with time_it("Generating useless JSON"):
    time.sleep(1)
    # If this raises an error, the timer still logs how long it suffered before dying.

Stop writing manual cleanup boilerplate. Use with, write predictable context managers, and keep your terminal output clean. Until next time, keep your logic straightforward and your exceptions loud.


Published by the Old Lane Developer Desk.

Disclaimer: This article was generated and formatted with the assistance of Artificial Intelligence.