Skip to content

Latest commit

 

History

History
79 lines (73 loc) · 3.13 KB

File metadata and controls

79 lines (73 loc) · 3.13 KB

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