A quick introduction to Python decorators
Decorators were introduced in Python 2.4 to provide a clean syntax for function wrappers. New syntax was not only applied to already existing Python built-in wrappers, but also enabled programmers to elegantly wrap any function or method with additional functionality.
According to the Python Glossary, a decorator is a function returning another function. This is a pretty vague description, so maybe it’s best to take a look at some code.
Next few lines describe how a decorator body looks like in general case:
def decorator_name(function):
def wrapper(*args):
# 1. Do some preprocessing.
# ...
# 2. Call 'function' with given arguments.
function(*args)
# 3. Do some postprocessing.
# ...
return wrapper
Bear in mind that the wrapper function must have the same signature as the decorated function. To be able to decorate any function, the template wrapper takes a tuple of non-keyword arguments (*args). Now, all that’s left is to actually apply the decorator:
@decorator_name
def some_func():
pass
Keep in mind that this is equivalent to:
def some_func():
pass
some_func = decorator_name(some_func)
So, the basic idea is simple – a decorator gives us an opportunity to do something before and after the decorated function gets called. Several simple examples are due:
1. Timing. To see how much time your functions consume, check the clock before and after the call, then print the difference:
import time
def timed(some_function):
def wrapper(*args):
start = time.clock()
result = some_function(*args)
end = time.clock()
print some_function.func_name, end - start
return wrapper
2. Printing and logging. Function arguments can easily be printed to console or logged to a file with decorators; same approach can be applied to return values. Decorator arguments can be used to divert logging to a different path without changing the decorator itself.
3. Debugging. You can check/assert argument values or types before the original function call. Note, however, that using isinstance() is usually discouraged (duck typing, remember?:).
Of course, this is just a tiny bit of all possible decorator uses. Make sure you check out Python Wiki for more examples and some inspiration.