Python Decorators

Add more functionality to your functions

Rupesh
2 min readJun 4, 2019

Decorators can be thought of as functions which modify the functionality of another function. It is a clean way of adding extra functionality to functions by using the “@” symbol. Also, it is a function which will accept another function as its parameter.

Functions:

Python uses the keyword called “def” to declare a function in it ,which stands for definition. The sample code is ,

>>> def medium():
... print("Hello Medium!")
...
>>> medium()
Hello Medium!

Here I have created a function called medium() which will print a statement “Hello Medium!”

In case of adding new features to this above function we can create a new function call “wrapper” which will extend its behaviour.

>>> def wrapper(fun):
... def inside():
... print("Extra Code Before Medium Function")
... fun()
... print("Extra Code After Medium Function")
... return inside

Let’s “decorate” our wrapper function by calling the decorator on it:

>>> func=wrapper(medium)

Let’s invoke the decorator as ,

>>> func()
Extra Code Before medium Function
Hello Medium!
Extra Code After medium Function

As you see the output of the above code, we find that the embedded function named inside is executed. This is because the decorator returns the inside function and later can be accessed on call. It is defined within the local scope of the wrapper, which means that the argument fun was accessed by the “inside” function such that it can be called. This is how Decorators work.

Lets do this in a more readable way using “@” symbol above the function

>>> def wrapper(func):
... def inside():
... print("Extra Code Before Medium Function")
... func()
... print("Extra Code After Medium Function")
... return inside
...
>>> @wrapper
... def medium():
... print("Hello Medium!")

Output:

>>> medium()
Extra Code Before Medium Function
Hello Medium!
Extra Code After Medium Function

The Statement @wrapper is equivalent to func=wrapper(medium).

Passing Arguments:

Here we are going to discuss how to pass parameters to decorators.

>>> def check(func):
... def validate(a,b):
... if b==0:
... print("ZeroDivisionError: division by zero")
... return
... else:
... return func(a,b)
... return validate
...
>>> @check # Decorator
... def div(a,b):
... return a/b

Output:

>>> div(1,0)
ZeroDivisionError: division by zero
>>> div(8,4)
2.0

As mentioned above,

  1. The div function will be passed as an argument to the check function and in turn, it will return the validate function.
  2. The validate function will accept the user’s parameters and execute if the dividend is not equal to Zero, else it will call and pass the args to div function which is referenced as func variable
  3. In case dividend is Zero, then print statement in validate function is executed as shown above.

Here I have included another example, where we can calculate the execution time of the functions.

>>> def timeit(func):
... def time_calc(arg):
... start=time.time()
... param=func(arg)
... print("Elapsed Time : {} Sec".format(time.time()-start))
... # return param
... return time_calc
...
>>> @timeit
... def main_func(num):
... temp=[]
... for itr in range(num):
... temp.append(itr)
... return temp
...
>>> main_func(10000000)
Elapsed Time : 0.8109278678894043 Sec

--

--