Example of a singly nested function with the module:
@decorator
def trace(f, *args, **kw):
print "calling %s with args %s, %s" % (f.func_name, args, kw)
return f(*args, **kw)Using the decorator module does require some nesting if your decorator takes arguments, eg:
def blocking(busy_message):
def blocking(f, *args, **kw):
#... implementation ...
return decorator(blocking)Decorator module also supports class-based decorators, eg:
async = decorator(Async(threading.Thread))…where Async is a class, and async is now the decorator you use with @async Really cool addition: Python 3.2 allows context managers to be callable, but the decorator module implements this for Python 2.5+
the decorator module, starting with release 3.4, offers a decorator.contextmanager decorator that solves both problems and works even in Python 2.5. The usage is the same and factories decorated with decorator.contextmanager will returns instances of ContextManager, a subclass of contextlib.GeneratorContextManager with a __call__ method acting as a signature-preserving decorator.
If you need the source of the original function for some reason, you can get it using:
inspect.getsource(factorial.__wrapped__)If you find a decorator online that doesn’t use the decorator module, if you’re too lazy to rewrite it, you can use this decorator instead:
def decorator_apply(dec, func):
"""
Decorate a function by preserving the signature even if dec
is not a signature-preserving decorator.
"""
return FunctionMaker.create(
func, 'return decorated(%(signature)s)',
dict(decorated=dec(func)), __wrapped__=func)Decorators, at least using the decorator module, can be affect performance:
python -m timeit -s "
from decorator import decorator
@decorator
def do_nothing(func, *args, **kw):
return func(*args, **kw)
@do_nothing
def f():
pass
" "f()"
python -m timeit -s "
from decorator import decorator
def f():
pass
" "f()"
Also, worth noting is that PEP 262 introduces a function signature object, so after Python 3.3, the decorator module is a bit superfluous
- The funcsigs package implements this functionality for Python 2.6, 2.7, and 3.2
- It’s not clear to me how one would use this to replicate the functionality of the decorator module, however
from funcsigs import signature
def foo(a, b=None, *args, **kwargs):
pass
sig = signature(foo)
#TODO: assign