Python Tutorial Python Advanced Python References Python Libraries

Python - Decorators



Decorators are powerful and useful tool in Python. It adds functionality to an existing code and modify the behavior of the code while compiling it. for example - It allows a programmer to wrap a function (a.k.a wrapper function) around a given function (a.k.a wrapped function) in order to modify the behavior of the given function, without permanently modifying it.

Create a Decorator

The decorator is created exactly same as any function in python and takes function as an argument. Inside decorator, a wrapper function is created which is wrapped around the function which is passed as an argument. See the syntax below:

Syntax

# defining decorator
def decorator_name(funct):
  def wrapper_function():
    statements
    funct
    statements
  return wrapped_function

Use a Decorator

To use a decorator with a function, a line containing @decorator name must be added above the function definition as shown in syntax below. Along with this, The argument definition of wrapped function must match inside and outside of the decorator.

Syntax

# use decorator with wrapped function
@decorator_name
def wrapped_function():
  statements

Example: function with no argument and not a return type

In the example below, a decorator called MyDecorator is created. Inside it, a wrapper function called MyWrapperFunction is created which prints a message just before and after execution of the wrapped function called MyFunction. The argument definition of wrapped function must match inside and outside of the decorator.

def MyDecorator(funct):
  def MyWrapperFunction():
    print("Before Execution")
    funct()
    print("After Execution")
  return MyWrapperFunction

@MyDecorator
def MyFunction():
  print("Hello World!")

MyFunction()

The output of the above code will be:

Before Execution
Hello World!
After Execution

Example: function with arguments and not a return type

In the example below, wrapped function called MyFunction takes two numbers as arguments and prints the sum of those numbers with a given message. As mentioned above, the argument definition of the wrapped function must match inside and outside the decorator, hence a and b arguments are passed through wrapper function which is again passed through wrapped function inside the decorator. In this example, the wrapper function is defined to calculate the time taken by wrapped function to perform the execution of given task.

import time

def MyDecorator(funct):
  def MyWrapperFunction(a, b):
    start = time.time()
    funct(a, b)
    end = time.time()
    # 1 is added because the execution time is very small.
    print("Time taken by", funct.__name__, "is", 1+end-start)
  return MyWrapperFunction

@MyDecorator
def MyFunction(a, b):
  print("sum of", a, "and", b, "is", a+b, ".")

MyFunction(15, 10)

The output of the above code will be:

sum of 15 and 10 is 25 .
Time taken by MyFunction is 1.0000081062316895

Example: function with arguments and a return type

In the example below, wrapped function called MyFunction returns value. Hence, there must be a return statement inside the wrapper function to get return from wrapped function. Please note that, in this example, *arg, **kwarg parameters are used to match with the argument definition of wrapped function.

def MyDecorator(funct):
  def MyWrapperFunction(*arg, **kwarg):
    print("Before Execution.") 
    abc = funct(*arg, **kwarg)
    print("After Execution.") 
    return abc
  return MyWrapperFunction

@MyDecorator
def MyFunction(a, b, c):
  print("Inside wrapped function.")
  return a + b + c

x = MyFunction(15, 10, 5)
print("The sum is", x)

The output of the above code will be:

Before Execution.
Inside wrapped function.
After Execution.
The sum is 30