Python Programming (136 Blogs) Become a Certified Professional
AWS Global Infrastructure

Data Science

Topics Covered
  • Business Analytics with R (26 Blogs)
  • Data Science (20 Blogs)
  • Mastering Python (84 Blogs)
  • Decision Tree Modeling Using R (1 Blogs)
SEE MORE

How to Implement Decorators in Python?

Last updated on Apr 24,2020 1.6K Views


Decorators in Python are powerful tools in Python. It allows programmers to modify the behaviour of function or class. Decorators allow to wrap another function to extend the behaviour of the wrapped function, without modifying it. This article will brief the following topics.

Let us begin!

 

Decorators in  Python

Today, we are going to discuss very integral of python i.e. decorators. Decorators can be thought of as a very useful and powerful tool but only if used properly. In simple words: they are functions which modify the functionality of other functions. They help to make our code shorter and more Pythonic.

Definition:
A decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure. Decorators are usually called before the definition of a function you want to decorate.

Python Logo- decorators- in-python

Warning: They are so confusing at first sight, So, tighten your belts because we are going for a deep dive!

Before diving straight, we will take a look at a few of the things that you should know prior to understanding Decorators.
Functions in Python are First Class Citizens. This means that they support operations such as being passed as an argument, returned from a function, modified, and assigned to a variable.

Now, let us look into Function that can be passed as an argument

 

A function can be passed as an argument

You must know about this and if you do not then firstly visit the following link and then come back.

Now, As functions are objects and functions accept objects as arguments, We may conclude that we can pass function to a function. Let’s understand it in a better way with some code.

Due to the fact that every parameter of a function is a reference to an object and functions are objects as well, we can pass functions – or better “references to functions” – as parameters to a function.

def greet(name):
      return “Hey {}”.format(name)
def i_will_greet(greet,name=”Avikar):
      print(greet(name))
      print(“Welcome to the world of edureka”)
i_will_greet(greet)

As we can clearly see that function greet() has been passed as a parameter to the function i_will_greet().

//Output:

Hey Pallavi
Welcome to the world of edureka

 

Note: The function greet has been passed to i_will_greet with no parentheses. Because if you use parenthesis then it will not pass function but its definition.

Let’s consider one more example to make our basics concrete.

from math import sin,cos
def calculate(func):
       res=0
       for i in [1,2,3,4,5]:
              res+=func(i)
       return res
print(“the value of sin is {}”.format(calculate(sin)))
print(“the value of cos is {}”.format(calculate(cos)))

//Output:
The value of sin is 0.1761616497223787
the value of cos is -1.2358184626798336

 

Let us look into the second Function that can be defined within functions

 

Functions can be defined within functions

The concept of having or defining functions inside a function is completely new to C or C++ programmers. We already know about nesting and surprisingly we can nest our functions too i.e. we can define as many functions as we want within a function.

def tell_me():
      def question():
            print("is python boring")
     def answer():
            print("Definintely not. Silly!")
     question()
     answer()
     return "look now you know what to learn"

//Output:
is python boring?
Definitely not. Silly!
look now you know what to learn

 

As it can be easily understood that when tell_me() is called

  • Firstly the function question and answer are defined but not called.
  • Later functions are called within the function itself and a string is returned at the end to print().

To have a firm grasp, Let us consider one more example in which we are required to convert temperature from Celsius to Fahrenheit.

def temperature(t):
      def celsius2fahrenheit(x):
             return 9 * x / 5 + 32
      return (“It’s ”+str(celsius2fahrenheit(t)+” degrees! ”
print(temperature(35))

//Output:
95.0 degrees

 

Let us move onto the third Function that can return functions as well.

 

Functions can return functions as well

It is not necessary to execute a function within another function, we can return it as an output as well.

def bake_cake(flavor="chocolate"):
      print("place the base of cake and decorate it with {} and fruits".format(flavor))
      def cherry():
            return "place cherry at the top of your {} cake".format(flavor)
      return cherry
tasty = bake_cake("butterscotch")
print(tasty())

Output:
place the base of the cake and decorate it with butterscotch and fruits
place cherry at the top of your butterscotch cake

 

Let us consider a useful example in which we assume that we can pass any number of arguments(*args). For a better understanding visit Edureka Community.

We can generalize our factory function so that it can work for polynomials of arbitrary degree

Image- Decorators in Python- Edureka

def polynomial_creator(*coeff):
      def polynomial(x):
             for index,c in enumerate(coeff[::-1]):
                     res+=c*x**index
             return res
      return polynomial

The above polynomial_creator function when passed with coefficients of quadratic equation,

  • Defines the polynomial() function.
  • Returns the polynomial function.

Now if we can assign this returned function to a variable(as studied Earlier), we can directly use our wrapped function.

p1 = polynomial_creator(2, 3,-1)
p2 = polynomial_creator(1, 8, -1, 3, 2)
for x in range(-2, 2, 1):
       print(x, p1(x), p2(x))

Note that when p1(x) is called the coeff. are 2,3 and -1 which indicates that the polynomial() is defined when the polynomial_creator() is assigned to p1 or p2, but not called.

So when we call p1() or p2(), we will pass the arguments to the polynomial(x).

As we can see from the output,

  • Firstly, the polynomial_creator has been called twice for p1 and p2.
  • Later, for each print statement polynomial() has been called separately.

//Output:
-2   1  -56
-1  -2   -9
 0  -1    2
 1   4   13

 

Now let’s look into the last Function that can be assigned to a variable

 

The function can be assigned to a variable

Did you notice tasty=bake_cake(“butterscotch”) in above code? Yes, right! We can assign functions to variables too i.e. we create an alias of functions.
The usefulness of the above assignment is:

Even if you delete the function, you can still use it via the variable you created.
Try del bake_cake

With all this knowledge in our cylinder, we are ready for the dive. But, the drive wouldn’t last long if we do not have a diving mask(the very small but important part).
Closure (our diving mask)

Python allows a nested function to access the outer scope of the enclosing function. This is a critical concept in decorators.

For example, let us consider an outer and inner function with their variables.

def outer():
     var =10
     def inner():
           varb=30
           print(“value of var inside inner {}”.format(var))
           print(“value of varb inside inner is {}”.format(varb))
     inner()
     print(“value of var outside inner {}”.format(var))
     print(“value of var_b outside inner is {}”.format(varb))

//Output:
value of var inside inner 10
value of var_b inside inner is 30
value of var outside inner 10
Traceback (most recent call last):
File “<pyshell#5>”, line 1, in <module>
outer()

 

Moving on to Our First Decorator

 

Our First Decorator

To create a decorator:

  • we have a function or class which needs decoration.
  • A decorator function.
  • A wrapper function which will be returned.

To understand it properly, lets first consider an example:

def outer(func):
     print(&ldquo;inside outer&rdquo;)
     def inner()
            print("inside inner function&rdquo;)
            func()
            print(&ldquo;inside inner again&rdquo;)
     return inner

We have here defined inner() inside outer(). A function func is to be passed to the function as a parameter.

Now,

def need_decoration():
       print("inside function call")
need_decoration=outer(need_decoration)
inside outer
need_decoration()
inside inner function
inside function call
inside inner again

It’s easy to understand. RIGHT!

Here we have called outer() with function need_decoration() as its parameter. So when outer is called the first print statement is executed and a function inner() is defined with func as need_decoration and inner function is returned.

This returned function is stored in need_decoration.

Now, when need decoration is executed via parenthesis inner function is called.

Two important things you need to understand :

1. The difference between a function call and function definition.

import math
temp=math.sin #temp is assigned the function definition
temp(4)
-0.7568024953079282
temp=math.sin(4) #temp is assigned the value returned by function
print(temp)
-0.7568024953079282

2. One might think that as need_decoration has lost its original definition and assigned to inner(), what will happen when need_decoration is called from inner()?

If you are thinking that it may end into an endless loop where inner() calls func() as need_decoration() and need_decoration is again equivalent to calling inner() then trust me you are not the only one in this dilemma.

This is why decorators turn bit clumsy and tough to understand.

So, This does not happen at all. When you define inner via calling outer as
need_decoration=outer(need_decoration) inner() automatically stores the definition of need_decoration there. We will delve deeper into this later.

You must be thinking that where is “ @ “, the glory of decorators. You will be glad that you have already used it but in a hidden way.
need_decoration=outer(need_decoration)
can be replaced by
@outer above the definition of need_decoration. So after rewriting the above code

 
@outer
def need_decoration():
      print("inside function call")
inside outer
need_decoration()
inside inner function
inside function call
inside inner again

We can do a lot with decorators like Multiple decorators can be applied to a single function. But we will study this in the next article.

This brings us to the end of this article where we have learned how we can use Decorators in python with several examples. I hope you are clear with all that has been shared with you in this tutorial.

If you found this article on “Decorators In Python” relevant, check out the Edureka Python Certification Training, a trusted online learning company with a network of more than 250,000 satisfied learners spread across the globe. 

We are here to help you with every step on your journey and come up with a curriculum that is designed for students and professionals who want to be a Python developer. The course is designed to give you a head start into Python programming and train you for both core and advanced Python concepts along with various Python frameworks like Django.

If you come across any questions, feel free to ask all your questions in the comments section of “Decorators In Python” and our team will be glad to answer.

Upcoming Batches For Python Programming Certification Course
Course NameDateDetails
Python Programming Certification Course

Class Starts on 27th April,2024

27th April

SAT&SUN (Weekend Batch)
View Details
Python Programming Certification Course

Class Starts on 25th May,2024

25th May

SAT&SUN (Weekend Batch)
View Details
Comments
0 Comments

Join the discussion

Browse Categories

webinar REGISTER FOR FREE WEBINAR
REGISTER NOW
webinar_success Thank you for registering Join Edureka Meetup community for 100+ Free Webinars each month JOIN MEETUP GROUP

Subscribe to our Newsletter, and get personalized recommendations.

image not found!
image not found!

How to Implement Decorators in Python?

edureka.co