Resource Ownership and Context Managers¶
Page Maps¶
graph LR
family["Python Programming"]
program["Python Object-Oriented Programming"]
section["Resources Failures Safe Evolution"]
page["Resource Ownership and Context Managers"]
capstone["Capstone evidence"]
family --> program --> section --> page
page -.applies in.-> capstone
flowchart LR
orient["Orient on the page map"] --> read["Read the main claim and examples"]
read --> inspect["Inspect the related code, proof, or capstone surface"]
inspect --> verify["Run or review the verification path"]
verify --> apply["Apply the idea back to the module and capstone"]
Read the first diagram as a placement map: this page is one concept inside its parent module, not a detached essay, and the capstone is the pressure test for whether the idea holds. Read the second diagram as the working rhythm for the page: name the problem, study the example, identify the boundary, then carry one review question forward.
Why this lesson matters¶
Many object models fail for a boring reason: nobody can say who closes the file, ends the session, releases the lock, removes the temporary directory, or returns the network connection.
That is not a small operational detail. It is an ownership failure.
If ownership is unclear, cleanup becomes a habit instead of a guarantee. The system may look correct in a happy-path demo and still leak resources, hold stale locks, or leave half-open sessions in real use.
The core rule¶
Every resource needs an owner.
That owner is responsible for:
- acquiring it
- exposing it safely
- cleaning it up deterministically
- deciding what happens if setup or cleanup fails
If you cannot point to that owner quickly, the design is already weak.
What counts as a resource¶
Students often think only of files and sockets. The category is wider.
Resources include:
- files and directories
- database sessions and transactions
- locks and semaphores
- external clients with open connections
- temporary state that must be cleaned or finalized
- any object whose lifetime matters for correctness, not just convenience
The important question is not "does Python collect it eventually?" The important question is "does correctness depend on ending this lifetime at the right time?"
Why with matters¶
with is not style sugar. It is a lifetime contract.
A context manager says:
- setup happens here
- cleanup happens here
- cleanup still happens if the body raises
That deterministic boundary is why context managers belong in a course about design, not only in a syntax appendix.
This snippet is valuable because the ownership story is visible. The file is opened for one purpose, used inside one boundary, and released when that boundary ends.
Ownership should match responsibility¶
Do not let a low-level helper open a resource while a distant caller silently owns the cleanup burden. That split is where leaks start.
Better patterns look like this:
- a repository owns its session boundary
- a unit of work owns the repositories and their shared lifetime
- an adapter owns the client connection it opens
- a higher layer passes already-owned dependencies when it truly controls the lifetime
The point is alignment. The layer that creates or governs the resource should also own the rule for ending it.
Writing your own context manager¶
When your code owns a non-trivial resource, the interface should make that ownership obvious.
class AlertStore:
def __enter__(self) -> "AlertStore":
self._connection = connect_to_store()
return self
def __exit__(self, exc_type, exc, tb) -> bool:
self._connection.close()
return False
Two teaching points matter here:
__exit__should usually returnFalseso exceptions still propagate- cleanup should be reliable even when the work inside the block fails
If the code suppresses exceptions without a very deliberate policy, the boundary stops being trustworthy.
Nested and shared lifetimes¶
Real systems often use more than one resource at once:
- a session plus a lock
- a client plus a temporary file
- a unit of work plus an event buffer
You still want one readable answer to "what closes what?"
Use structured lifetime tools when the set is static, and use ExitStack when the set
is dynamic. The important thing is not which helper you chose. The important thing is
that the lifetime remains explicit and reviewable.
What not to rely on¶
Avoid vague cleanup stories such as:
- "the caller will remember to close it"
- "garbage collection will take care of it"
- "we only use it briefly, so it is probably fine"
- "tests never showed a leak"
Those are not ownership rules. They are hope.
__del__ is especially poor as a main cleanup strategy because it does not give the
deterministic boundary this module is trying to teach.
Common mistakes¶
- opening resources in constructors and never defining a visible lifetime boundary
- returning open resources to callers without documenting ownership transfer
- mixing business logic with manual open-close choreography in many places
- suppressing cleanup-time failures without deciding who now owns the damage
- using global singletons for convenience when the real problem is unclear ownership
These mistakes usually come from hiding lifetime decisions instead of modeling them.
Review checklist¶
| Question | Good sign |
|---|---|
| can you name the owner of each non-trivial resource? | yes |
| is acquisition paired with deterministic cleanup? | yes |
| does the interface make lifetime visible rather than implicit? | yes |
| are exceptions propagated unless a deliberate policy says otherwise? | yes |
Capstone connection¶
In the capstone, the runtime facade, repository boundary, and in-memory unit of work are all small examples of lifetime ownership.
Ask these questions while reviewing them:
- who opens the resource-like boundary?
- who ends it?
- what still happens when the operation raises?
If the answer is fuzzy, the capstone structure is still hiding one of its most important contracts.
Exit check¶
Leave this lesson only when you can do all of these:
- explain why resource cleanup is an ownership question, not a syntax question
- identify one place where
withexpresses design intent rather than mere convenience - point to one capstone boundary and name the object that owns its lifetime