Function decorators in python
This is nice python syntax sugar that may look like magic but really isn't. It can be used for quick and easy AOP, registering functions with objects... you name it.
Introduction
Python decorators are objects that are called, returning a function that wraps the function they decorate, taking the wrapped function object as an argument and replacing it with the wrapper function.
A simple decorating function can look like this:
def decorator(func):
def wrapper(*args):
return 'x' + func(*args) + 'x'
return wrapper
and is used to decorate another function like this:
@decorator
def test():
return "hello"
Calling test
will now return the string "xhellox". *
prefixed arguments
will accept an arbitrary number of arguments, putting them into a tuple, and
can be dereferenced into arguments again with *
in a function call. We use
this to pass all the non-keyword arguments in the wrapping function to the
wrapped function. Keyword arguments can similarly be extracted from
dictionaries using **
and turned back into arguments in a function call with
**
again.
This is good to know if you just want a "pass-through" decorator (maybe some sort of "logging" aspect) that works for any function or method.
Dynamically creating decorators
The simple example above can be extended to support different appending different characters, but the object following the "@" in the decorator still needs to resolve to a function. What if we could decorate as such:
@decorator('$')
def test():
return "hello"
>>> test()
'$hello$'
The decorating function can now no longer be the function you use to generate
it, but the function it returns. The decorator
in the example above would be
a misnomer.
def decorator_factory(prefix)
def dec(func): # the actual decorator
def wrapper(*args):
return prefix + func(*args) + prefix
return wrapper
return dec
@decorator_factory('$')
def test():
return "hello"
>>> test()
'$hello$'
Decorators as classes or class members
A decorator can be any callable object. This includes classes and any object
that implements __call__