Function acting as both decorator and context manager in Python?

Jacob Oscarson picture Jacob Oscarson · Feb 9, 2012 · Viewed 19.1k times · Source

This might be pushing things a little too far, but mostly out of curiosity..

Would it be possible to have a callable object (function/class) that acts as both a Context Manager and a decorator at the same time:

def xxx(*args, **kw):
    # or as a class

@xxx(foo, bar)
def im_decorated(a, b):
    print('do the stuff')

with xxx(foo, bar):
    print('do the stuff')

Answer

Sven Marnach picture Sven Marnach · Feb 9, 2012

Starting in Python 3.2, support for this is even included in the standard library. Deriving from the class contextlib.ContextDecorator makes it easy to write classes that can be used as both, a decorator or a context manager. This functionality could be easily backported to Python 2.x -- here is a basic implementation:

class ContextDecorator(object):
    def __call__(self, f):
        @functools.wraps(f)
        def decorated(*args, **kwds):
            with self:
                return f(*args, **kwds)
        return decorated

Derive your context manager from this class and define the __enter__() and __exit__() methods as usual.