Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function acting as both decorator and context manager in Python?

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') 
like image 859
Jacob Oscarson Avatar asked Feb 09 '12 15:02

Jacob Oscarson


People also ask

What are the functions of context managers in Python?

Context managers allow you to allocate and release resources precisely when you want to. The most widely used example of context managers is the with statement. Suppose you have two related operations which you'd like to execute as a pair, with a block of code in between.

Is decorator a function in Python?

A decorator in Python is a function that takes another function as its argument, and returns yet another function . Decorators can be extremely useful as they allow the extension of an existing function, without any modification to the original function source code.

Which of the following keywords is used to enable a context manager in Python?

Python provides an easy way to manage resources: Context Managers. The with keyword is used. When it gets evaluated it should result in an object that performs context management. Context managers can be written using classes or functions(with decorators).

Which function is a decorator?

A decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure. Decorators are usually called before the definition of a function you want to decorate.


2 Answers

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.

like image 64
Sven Marnach Avatar answered Sep 25 '22 21:09

Sven Marnach


In Python 3.2+, you can define a context manager that is also a decorator using @contextlib.contextmanager.

From the docs:

contextmanager() uses ContextDecorator so the context managers it creates can be used as decorators as well as in with statements

Example usage:

>>> from contextlib import contextmanager >>> @contextmanager ... def example_manager(message): ...     print('Starting', message) ...     try: ...         yield ...     finally: ...         print('Done', message) ...  >>> with example_manager('printing Hello World'): ...     print('Hello, World!') ...  Starting printing Hello World Hello, World! Done printing Hello World >>>  >>> @example_manager('running my function') ... def some_function(): ...     print('Inside my function') ...  >>> some_function() Starting running my function Inside my function Done running my function
like image 29
Mark Amery Avatar answered Sep 21 '22 21:09

Mark Amery