__enter__ / __exit__

Updated March 18, 2026 · Dunder Methods
python context-manager dunder-methods

Introduction

Python’s __enter__ and __exit__ methods form the context manager protocol, which powers the with statement. This protocol provides a clean way to manage resource setup and teardown, ensuring that cleanup code runs reliably regardless of whether the block executes successfully or raises an exception.

The Protocol

__enter__(self)

This method is called when entering the with block. It can return any object, which becomes bound to the variable after the as keyword:

def __enter__(self):
    # Setup logic here
    return self  # The object bound to 'as' in 'with ... as x:'

__exit__(self, exc_type, exc_value, exc_tb)

This method is called when exiting the with block, regardless of how the block ends. It receives information about any exception that occurred:

def __exit__(self, exc_type, exc_value, exc_tb):
    # Cleanup logic here
    # Return True to suppress the exception
    return False

The parameters are:

  • exc_type — Exception class (e.g., ValueError) or None if no exception occurred
  • exc_value — Exception instance or None
  • exc_tb — Traceback object or None

Practical Examples

Basic Resource Management

class DatabaseConnection:
    def __enter__(self):
        print("Connecting to database...")
        self.connection = "db_connection_object"
        return self

    def __exit__(self, exc_type, exc_value, exc_tb):
        print("Closing database connection...")
        self.connection = None
        return False

with DatabaseConnection() as db:
    print(f"Using: {db.connection}")

Output:

Connecting to database...
Using: db_connection_object
Closing database connection...

Suppressing Specific Exceptions

You can selectively suppress certain exceptions while allowing others to propagate:

class IgnoreValueError:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, exc_tb):
        if exc_type is ValueError:
            print(f"Suppressing ValueError: {exc_value}")
            return True  # Suppress this exception
        return False  # Let other exceptions propagate

# This exception is suppressed
with IgnoreValueError():
    raise ValueError("This will be suppressed")

# This exception propagates
try:
    with IgnoreValueError():
        raise TypeError("This will NOT be suppressed")
except TypeError:
    print("TypeError was propagated correctly")

Logging Exceptions

The __exit__ method can access exception details for logging or custom handling:

class ExceptionLogger:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, exc_tb):
        if exc_type is not None:
            print(f"Exception: {exc_type.__name__}: {exc_value}")
        else:
            print("No exception occurred")
        return False

with ExceptionLogger():
    x = 1 / 0

Output:

Exception: ZeroDivisionError: division by zero

Common Patterns

Returning a Different Object

The object returned by __enter__ (not the context manager itself) is bound to the as variable:

class Outer:
    def __enter__(self):
        return "returned_value"

with Outer() as x:
    print(x)  # Prints: returned_value

Conditional Suppression

Handle different exception types differently:

def __exit__(self, exc_type, exc_value, exc_tb):
    if exc_type is ValueError:
        print("Handling ValueError")
        return True  # Suppress
    elif exc_type is TypeError:
        print("Handling TypeError, will re-raise")
        return False  # Re-raise
    return False

See Also

  • __init__ — Initialize objects when created
  • __del__ — Cleanup when objects are garbage collected
  • __call__ — Make instances callable like functions

Summary

MethodPurposeReturn Value
__enter__Setup resourcesObject bound to as clause
__exit__Cleanup and exception handlingTrue to suppress, False/None to propagate

The context manager protocol is ideal for managing resources that require explicit cleanup, such as files, database connections, locks, and temporary files. It guarantees that cleanup code runs even when exceptions occur, making your code more reliable and readable.