Search code examples
pythoncontextmanager

Why is @contextmanager used only for self-contained functions?


I am reading the Python Cookbook where the following is mentioned:

@contextmanager is really only used for writing self-contained context-management functions. If you have some object (e.g. a file, network connection, or lock) that needs to support the with statement, you still need to implement the __enter and __exit__ methods separately.

I can't quite understand this. Why can't we use a file object with a context-management function? Aren't functions decorated with @contextmanager equivalent to classes with __enter__ and __exit__ methods?


Solution

  • Say you've got a class:

    class DatabaseCursor(object):
        ...
    

    and you want to add context manager functionality to it. Where would you put @contextmanager?

    Not here:

    @contextmanager
    class DatabaseCursor(object):
        ...
    

    Not here:

    class DatabaseCursor(object):
        @contextmanager
        def __init__(self, ...):
            ...
    

    Not here:

    class DatabaseCursor(object):
        @contextmanager
        def __enter__(self):
            ...
    

    Nowhere, really. @contextmanager doesn't help you add context manager functionality to existing classes. You can't even use @contextmanager-decorated functions as base classes, because the implementation doesn't actually create a class. If you want your file-like object or database cursor or network connection or other closeable resource to support use as a context manager, you have to implement __enter__ and __exit__ directly.