Context Manager

An object usable with with that guarantees its setup and cleanup code run together — even if an exception happens in between.

                with expression as name:
    ...

              

Purpose

A with statement pairs setup and cleanup: it runs the setup, hands you the result, then guarantees the cleanup runs afterward — whether the block finished normally or raised an exception. An open file is the example nearly everyone meets first.

Example

with open("notes.txt", encoding="utf-8") as f:
    contents = f.read()
# f is guaranteed closed here, even if .read() had raised
config_path.write_text(json.dumps(config), encoding="utf-8")   # no with needed —
                                                                  # write_text opens and closes internally

Behavior notes

  • Any object implementing __enter__ and __exit__ can be used after with — files, locks, database transactions, and many testing utilities all do this. __enter__ runs at the start of the block (its return value is what as name binds); __exit__ always runs at the end, exception or not.
  • with expr as name: is equivalent in spirit to a try/finally that calls the setup and cleanup methods for you — the real value is that it’s impossible to forget the cleanup call, the way it’s easy to forget a manual f.close() after an early return or a raised exception.
  • Several convenience methods (Path.write_text, Path.read_text, json.dump given an already-open file) handle opening and closing internally, so a with block isn’t always needed just because a file is involved — reach for it when a file object is used directly.

Common mistakes

  • Opening a file without with (f = open(path); f.read()) and relying on it eventually getting closed — it might not be, especially if an exception is raised between opening and an explicit close() call that never runs.
  • Nesting several separate with statements for multiple resources instead of combining them into one (with open(a) as fa, open(b) as fb:), which reads more clearly for a fixed, known set of resources.

Implementation notes

The context-manager protocol (__enter__/__exit__ and what “always runs” guarantees) is defined by the language’s data model — identical across conforming implementations.

Taught in these lessons

Related reference