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.