Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

A Python context manager wraps a block of code with setup and cleanup. The with statement calls its entry method, runs the block, and then calls its exit method—even when the block raises an exception, as long as entry completed successfully. Use this pattern for files, locks, temporary state, and other resources that need a defined lifetime.

What a context manager does

A context manager establishes a runtime context around a with block. A common example is opening a file: the file is available inside the block and is closed when the block ends. Context managers can also acquire and release locks or save and restore state. The Python Language Reference describes the precise behavior of with.

with open("notes.txt", "r", encoding="utf-8") as file:
    contents = file.read()

Read this as “enter the file’s managed lifetime, use it, then leave that lifetime.” The cleanup is not merely a line that runs after the block in the normal case; it is part of the statement’s exit behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How with calls __enter__ and __exit__

For with expression as target:, Python evaluates the expression, obtains the manager’s special methods, and calls __enter__(). If an as target is present, Python binds the value returned by __enter__() to it. After the block, Python calls __exit__().

The Python Language Reference guarantees that if __enter__() returns without an error, __exit__() will be called. If entry itself fails, the block is not entered and this guarantee does not apply.

  • If the block finishes normally, __exit__() receives None for the exception type, value, and traceback.
  • If an exception leaves the block, __exit__() receives its type, value, and traceback.
  • A truthy return from __exit__() suppresses the exception. A false value, including None, lets it propagate.

Therefore, returning a truthy value is a deliberate decision to handle an exception, not a default cleanup behavior. Most managers should allow unexpected exceptions to propagate.

Implement a manager as a class

Define __enter__() and __exit__() when the manager needs to hold state, has multiple operations, or benefits from explicit methods that reviewers can inspect.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
class ManagedValue:
    def __enter__(self):
        self.value = acquire_value()
        return self.value

    def __exit__(self, exc_type, exc_value, traceback):
        release_value(self.value)
        return False

with ManagedValue() as value:
    use(value)

This is an illustrative pattern: replace the placeholder function names with real acquisition, use, and release operations. Returning False makes clear that exceptions from the block should not be suppressed. Returning None has the same effect.

The object returned from __enter__() is what the optional as target receives; it need not be the manager object itself. Python performs the protocol lookup as part of the with statement.

Write a generator-based manager with @contextmanager

For a simpler lifetime that naturally reads as “set up, yield the resource, clean up,” use contextlib.contextmanager. Put acquisition before the single yield and cleanup in a finally block.

from contextlib import contextmanager

@contextmanager
def managed_resource():
    resource = acquire_resource()
    try:
        yield resource
    finally:
        release_resource(resource)

with managed_resource() as resource:
    use(resource)

The decorated function must produce a generator iterator that yields exactly once. Code before yield runs as the block is entered; code after it resumes as the block exits. The finally clause ensures the release operation is reached during normal exit and exception unwinding.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If the block raises an exception that is not suppressed, contextmanager raises it at the yield point inside the generator. If you catch it only to log or perform cleanup, re-raise it; otherwise the generator can make the manager treat it as handled.

Choose the class or generator pattern

Consideration Class-based manager @contextmanager
Shape of the logic Entry and exit are separate methods; useful when each has substantial logic. Setup and cleanup surround one yield; concise for a single clear lifetime.
State and branching Can retain state on the manager instance and represent multiple steps explicitly. Local variables around the yield often keep simple state compact.
Exception handling Inspect exception arguments in __exit__(); return truthy only to suppress intentionally. Handle exceptions around yield; re-raise those that should propagate.
Reuse, reentrancy, or async work Can be designed for these needs, but they are not guaranteed by the protocol. Generator-based managers should generally be recreated for each use; asynchronous lifetimes use a separate API.

Neither implementation is universally better. Prefer the form that makes resource ownership, cleanup, and exception behavior clearest. Consult the official contextlib documentation for the standard-library utilities and their version-specific details.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Useful tools in contextlib

  • closing(obj) calls obj.close() when the block exits, useful for objects that have close() but do not implement the context-manager protocol. Prefer native support when available; for example, urlopen() already works with with.
  • nullcontext(value) is a no-op manager whose entry value is value. It can simplify a function that accepts either an already-open resource or a path from which it opens one.
  • suppress(SomeSpecificError) ignores only the listed exception types. Use it only when continuing after those specific errors is known to be correct.
  • ExitStack manages a dynamic set of contexts and cleanup callbacks. It unwinds them in reverse registration order, like nested with statements, and is useful when resource count is determined at runtime or a later acquisition might fail.

Use asynchronous context managers for awaited setup or cleanup

async with is a distinct protocol for asynchronous code. It uses __aenter__() and __aexit__(); contextlib.asynccontextmanager provides the generator-based form. Use these when entering or exiting the context must await asynchronous work, rather than treating synchronous with and asynchronous setup as interchangeable.

Common mistakes to avoid

  • Assuming cleanup suppresses errors: cleanup and suppression are separate. Unless the exit method returns truthy, the exception propagates.
  • Forgetting finally in a generator manager: put essential release logic there so it runs when the block exits exceptionally.
  • Swallowing an exception after logging: re-raise it unless suppression is intentional.
  • Reusing every manager instance: reuse and reentrancy depend on the particular manager. The documentation specifically cautions that file objects and managers produced by @contextmanager should be recreated for each use.
  • Using a helper without checking Python compatibility: the current Python documentation covers 3.14.8 and records version additions or changes for individual helpers. Check the documentation for the Python version your program supports before depending on a helper.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.