Its very important to remember that in Python, everything is an object.
Functions are objects, classes are also objects. By virtue of being objects, they can be passed around. And they are mutable (which means they can be modified).
Think of a situation where you want to measure the time each function takes to execute. Assume you have 20 functions in your module that you want to measure the execution time for.
def function1(*args): # do something. def function2(*args): # do something. . . def function20(*args): # do something.
And you don’t want to modify the 20 functions to put the time measurement code in.
The way to solve this elegantly is to wrap each of the 20 functions in an other function that does the measurement of execution time like this…
def measure_time_decorator(func): # the function that wraps the func that is passed in. def _wrapper(*args): start_time = time.time() res = func() end_time = time.time() print 'the function took %f seconds' % (end_time - start_time) return res # the wrapper is returned and it will replace the func that is passed in. return _wrapper function1 = measure_time_decorator(function1) function2 = measure_time_decorator(function2) function3 = measure_time_decorator(function3) . . function20 = measure_time_decorator(function20)
That’s it. Now, whenever the functions are called, they actually execute the _wrapper() function inside the measure_time_decorator() function.
The way we assign the return value of measure_time_decorator back to the functions may look a bit clunky. Python has a bit more cleaner way of doing this using the decorator syntactic sugar.
@measure_time_decorator def function1(*args): # do something.
By adding @measure_time_decorator on a line before the definition of a function does exactly what the below line does.
function1 = measure_time_decorator(function1)
Happy decorating!