The Library Method: Understanding Context Managers
Context managers aren’t magic – they’re Python’s way of automating try/finally for guaranteed cleanup
Timothy enters the library and heads to Margaret’s desk.
Timothy: “Margaret, I’ve been using with statements, but I don’t understand how they work.”
Margaret: “Show me.”
Timothy: types
class FileManager:
def __enter__(self):
print("Opening resource")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Closing resource")
return False
with FileManager() as fm:
print("Using resource")
Output:
Opening resource
Using resource
Closing resource
Timothy: “It prints in that order – but how does Python guarantee ‘Closing resource’ prints even if there’s an error?”
Margaret: “Let’s use the method to understand it.”
Structured English
Margaret: writes on paper “Here’s what’s happening:”
What a context manager does:
- An object with two special methods:
__enter__and__exit__ - When you write
with SomeObject() as x:, Python does four things:- Calls
__enter__()→ runs setup code, returns a value - Assigns that value to
x - Runs your code block
- Calls
__exit__()→ runs cleanup code no matter what
- Calls
- The key:
__exit__always runs, even if there’s an error - It’s like an automatic try/finally block built into the syntax
Timothy: “So with guarantees the cleanup?”
Margaret: “Yes. Let’s prove it with Pascal.”
Expected Output:
Opening resource
Using resource
Closing resource
Pascal as Pseudocode
Margaret: opens the Pascal compiler
program ContextManagerDemo;
type
TFileManager = record
active: Boolean;
end;
{ This is like __enter__ }
procedure EnterContext(var fm: TFileManager);
begin
WriteLn('Opening resource');
fm.active := True;
end;
{ This is like __exit__ }
procedure ExitContext(var fm: TFileManager);
begin
WriteLn('Closing resource');
fm.active := False;
end;
var
fm: TFileManager;
begin
{ Three-phase pattern: Enter -> Use -> Exit }
EnterContext(fm); { 1. Acquire resource }
WriteLn('Using resource'); { 2. Use resource }
ExitContext(fm); { 3. Release resource }
{ Note: In production Pascal code, you would wrap steps 2-3 }
{ in a try-finally block to guarantee cleanup happens even }
{ with errors. The pattern is the same - structured setup }
{ and guaranteed cleanup. }
end.
Output:
Opening resource
Using resource
Closing resource
Margaret: “See? Three clear phases: enter, use, exit. In production Pascal code, you’d wrap this in a try-finally block to guarantee the exit always runs, even with errors. But the pattern is the same – structured resource management with guaranteed cleanup.”
Human Readable Python
Timothy: “Let me write what with is doing behind the scenes.”
class FileManager:
def __enter__(self):
print("Opening resource")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Closing resource")
return False
# This is what "with" does automatically:
fm = FileManager()
context_value = fm.__enter__() # Calls setup, stores result
try:
print("Using resource")
finally:
# Always calls cleanup, passing exception info if there was an error
# (None, None, None means no exception occurred)
fm.__exit__(None, None, None)
Output:
Opening resource
Using resource
Closing resource
Timothy: “Same output – so with is just wrapping it in try/finally.”
The Revelation
Margaret: “Now look at the original code again.”
class FileManager:
def __enter__(self): # ← Called first (setup)
print("Opening resource")
return self # ← This becomes the 'as' variable
def __exit__(self, exc_type, exc_val, exc_tb): # ← Always called (even on error)
print("Closing resource") # ← Cleanup happens here
return False # ← Don't suppress exceptions
with FileManager() as fm: # ← Creates try/finally automatically
print("Using resource") # ← Your code runs in the try block
Output:
Opening resource
Using resource
Closing resource
Timothy: “So with is automatic resource management using try/finally.”
Margaret: “Exactly. The __exit__ method always runs, guaranteeing cleanup. That’s why files close automatically, locks release, connections close – the cleanup is guaranteed.”
Summary
🎯 What We Proved:
All three implementations produced identical output showing guaranteed cleanup.
💡 What We Learned:
- Context managers have
__enter__(setup) and__exit__(cleanup) methods -
withstatement automatically wraps code in try/finally -
__exit__always runs, even if there’s an error - This guarantees resource cleanup
🔧 The Library Method:
- Structured English – Setup, use, cleanup with guarantee
- Pascal as Pseudocode – try/finally showing the guarantee
-
Human Readable Python – Explicit version of what
withdoes -
Understanding –
withautomates the try/finally pattern
Key Insight: Context managers aren’t magic – they’re Python’s way of automating try/finally for guaranteed cleanup. Whether you use with or explicit try/finally, you now understand the mechanism.
Next in The Library Method: Understanding @property – How do methods act like attributes?
Aaron Rose is a software engineer and technology writer at tech-reader.blog and the author of Think Like a Genius.