Python 3.2 enhanced contextlib.contextmanager so that it is possible to use a context manager as a decorator. For instance, given the contextmanager factory below
@contextmanager def before_after(): print(before) yield print(after) it is possibile to use it to generate decorators: @before_after() def hello(user): print('hello', user) This is equivalent to the more traditional def hello(user): with before_after(): print('hello', user) but it has the advantage of saving a level of indentation and we all know that flat is better than nested. Cool, but there are three issues: 1. I am using Python 2.7, not Python 3.2, so contextmanager has not such feature 2. The contextmanager decorator is losing the signature of the before_after factory: >>> help(before_after) Help on function before_after in module __main__: before_after(*args, **kwds) 3. before_after() decorators do not preserve the signature of the decorated function either. Since I am the author of the decorator module I have easily found out a recipe to solve both issues. Here it is: from decorator import decorator, FunctionMaker from contextlib import GeneratorContextManager class GeneratorCM(GeneratorContextManager): def __call__(self, func): return FunctionMaker.create( func, "with _cm_: return _func_(%(shortsignature)s)", dict(_cm_=self, _func_=func), __wrapped__=func) @decorator def contextmanager(func, *args, **kwds): return GeneratorCM(func(*args, **kwds)) before_after() objects obtained by using this version of contextmanager become signature-preserving decorators. I am not going to explain how FunctionMaker performs its magic (hint: it uses eval), but I am asking a question instead: should I add this feature to the next release of the decorator module? Do people use the context-manager-as-decorator functionality? It is quite handy in unit tests and actually I think it came from the unittest2 module. But I am reluctant to complicate the API of the module, which currently is really really small and such has been for many years. -- http://mail.python.org/mailman/listinfo/python-list