๐Ÿ“with Statement, __enter__/__exit__, contextlibLESSON

Context Managers: with Statement, enter/exit, contextlib

The with statement solves a pervasive problem: ensuring that resources are always cleaned up, even when exceptions occur. Files must be closed, locks must be released, database transactions must be committed or rolled back. Context managers make this automatic.

The with Statement

The with statement:

  1. Calls __enter__() on the context manager
  2. Binds the return value to the as variable (if present)
  3. Executes the body
  4. Calls __exit__() โ€” always, even if an exception occurred

enter and exit

To make a class a context manager, implement these two methods:

exit Parameters

__exit__(self, exc_type, exc_val, exc_tb) receives three arguments:

  • exc_type: the exception class, or None if no exception
  • exc_val: the exception instance, or None
  • exc_tb: the traceback object, or None

Return True to suppress the exception (swallow it โ€” execution continues after the with block). Return False or None to let it propagate.

Database Transaction Pattern

A classic context manager use case:

contextlib.contextmanager โ€” Generator-Based Context Managers

The @contextmanager decorator lets you write context managers as generator functions. Everything before yield is the __enter__ logic; the yielded value is bound to as; everything after yield is the __exit__ logic:

To handle exceptions in a @contextmanager, wrap the yield in try/except:

contextlib.suppress

contextlib.suppress(*exceptions) is a pre-built context manager that silently suppresses specified exceptions:

contextlib.nullcontext

nullcontext(enter_result=None) is a no-op context manager โ€” useful when a context manager is optional:

Multiple Context Managers

You can open multiple context managers in one with statement:

Timing Example

A common use case โ€” measuring how long a block takes:

Knowledge Check

What does `__exit__` returning `True` do?

In a `@contextmanager` generator, where is the `__enter__` logic placed?

What is `contextlib.nullcontext` used for?