Decorators in Python
Bhaskar S | 04/18/2015 |
Introduction
Often times there is a need to modify the behavior of one or more functions (or methods) without actually modifying them. For example, we want to monitor some functions (or methods) for their performance by timing them. How do we do that in Python without explicitly modifying those functions (or methods) ??? Enter Decorators in Python.
A Decorator in Python is a function that dynamically alters the behavior of another function without actually modifying it.
Decorators in Python are nothing more than wrapper functions that leverage functional programming constructs (higher-order functions, in particular) to achieve the desired functionality.
In the article Python Quick Notes :: Part - 6, we learnt about the functional programming constructs such as First Class objects and Higher Order functions. Also, from the article Introspection in Python, we learnt that every entity in Python is an object - be it a module, a package, a class, a method, a function, or a type.
The following is a simple python program named DecoratorsOne.py that invokes three functions:
Executing DecoratorsOne.py produces the following output:
DecoratorsOne:: <main> :: alice = ('alice', 'Alice', 'Painter') DecoratorsOne:: <main> :: bob = ('bob', 1217.34) DecoratorsOne:: <main> :: carol = ('carol', 123.91)
We want to instrument the functions get_customer_info, get_deposit_amt, and get_credit_amt to monitor for their performance.
The following is a simple python program named DecoratorsTwo.py that demonstrates how to implement and use Decorators in Python:
Executing DecoratorsTwo.py results in the following output:
DecoratorsTwo:: <time_decorator> :: get_customer_info took 1.00109291077 ms DecoratorsTwo:: <main> :: alice = ('alice', 'Alice', 'Painter') DecoratorsTwo:: <time_decorator> :: get_deposit_amt took 1.00104689598 ms DecoratorsTwo:: <main> :: bob = ('bob', 1217.34) DecoratorsTwo:: <time_decorator> :: get_credit_amt took 1.0010509491 ms DecoratorsTwo:: <main> :: carol = ('carol', 123.91)
In the Python program DecoratorsTwo.py, the function time_profiler(func) is the Decorator function that takes another function (func) as an argument and returns a modified version of the function (func) that transparently implements the performance measurement functionality we desire.
The inner function function_wrapper(*args, **kwargs) is where the core logic implemented. The arguments of the inner function are:
*args - syntax used to pass variable number of positional arguments to a function
**kwargs - syntax used to pass variable number of keyword based arguments to a function
To use the Decorator function, prepend each function definition with the @ symbol followed by the Decorator function name (time_profiler in our example). Thats it !!!
References