What are Decorators
A decorator is a callable that takes another function as argument and returns a new function as output. It’s used in the following way:
@logthis
def perform_action(n):
....
....
Decorators come under Metaprogramming i.e changing program behaviour at runtime.
Example
Decorators are executed right after the decorated function is defined. That is usually at import time. The following decorator is used to find the execution time of a function
import time
from functools import wraps
def timeit(func):
"""
Reports the execution time
"""
@wraps(func)
def wrapper(*args,**kwargs):
start = time.time()
result = func(*args,**kwargs)
end = time.time()
print(func__name__,end - start)
return result
return wrapper
Example of using this decorator
@timeit
def exponentiation(b,n):
exp_iter(b, n, 1)
def exp_iter(b,counter,product):
if counter == 0:
print(product)
else:
counter = counter - 1
product = b * product
exp_iter(b,counter,product)
and the output will be
16
exponentiation 0.00020766258239746094
The use of wraps(func)
in the above code is there to preserve function metadata.This will help us in getting function metadata like:
exponentiation.__name__
exponentiation.__doc__
Defining a decorator that takes arguments
You can also define decorators that can accept arguments.For example let us take a decorator that adds logging to a function and allows the user to specify the loggin details:
from functools import wraps
import logging
def logger(level,name=None,message=None):
"""
A simple logger decorator that allows the
user to specify the logging details like
name and message
"""
def decorate(func):
logname = name if name else func.__module__
log = logging.getlogger(logname)
logmessage = message if message else func.__name__
@wraps(func)
def wrapper(*args,**kwargs):
log.log(level,logmsg)
return func(*args,**kwargs)
return wrapper
return decorate
Usage:
@logged(logging.DEBUG)
def add(x,y):
return x + y
Decorators are definately an useful functionality.There are some advance decorator concepts that I will write about next, these are:
- Defining decorators inside classes
- Defining decorators as classes