Python Decorators

Python Decorators

ยท

6 min read

Hello guys๐Ÿ‘‹๐Ÿ‘‹!! Welcome back to my second blogpost. In this post, we will be looking at Python Decorators along with some real-life examples. It took me a while to understand the concept of decorators. So, I thought of writing a blogpost which will make it easier to understand. Without further ado, let's jump right in!

minions-strong.gif

Python Decorators: - What is that???๐Ÿค”

A decorator is a function that takes another function and adds some functionality to it, without modifying it.

Don't worry, if you don't get it right away๐Ÿ˜•. It's always good to break a difficult concept into smaller pieces and connecting those pieces into that whole concept for better understanding. Let's break the decorators into pieces.

Before trying to understand decorators, we must know about the functions. Let's talk about the BIG 3 about functions.

the-falcon-and-the-winter-soldier-tfatws.gif

  • The first-class objects

  • Inner functions

  • Returning functions from functions


The first class objects:๐Ÿ˜Ž

Python functions are First-class citizens, meaning they can be passed as arguments, modified and can be assigned to a variable as any other python objects (ie., list, string, int..)

def my_name(name):
  return f'Hello {name}'


greet = my_name
greet('Python')

Output:

Hello Python

Explanation:

What is happening in that above block of code? First, we have assigned a variable greet to the defined function my_name. Then, we have passed an argument (value) Python to the variable greet which calls the function my_name.

This is the Python's first class objects. We can store the function in a variable, can store them in data structures such as lists, dictionaries., can be passed as a function and so on..


Inner Functions:๐Ÿ™‚

A function defined within another function. The order of function does not matter. The inner functions will only be defined when parent function is called. The inner functions are of local scope within parent functions. They are also called as nested functions.

def my_name(name):
  print f'My name is {name}'
  def first_name(first):
    print f'My first name is {first}'
  def last_name(last):
    print f'My last name is {last}'

    first_name('Python')
    last_name('Programming')


my_name('Python Programming')

Output:

My name is Python Programming
My first name is Python
My last name is Programming

Explanation:

In the above code snippet, we are defining a function my_name, which has two inner functions within it - first_name and last_name. The first_name and last_name scope are within the Parent function (my_name).


Returning Functions from Functions:๐Ÿ™ƒ

We saw that Python functions are first-class objects. That is, they can be passed as arguments and can also be returned as a value from another function. Let's see it in action.

def my_name():
  def first_name(name):
    return f'My first name is {name}'
  return first_name



greet = my_name()
greet('Python')

Output:

My first name is Python

Explanation:

When the PARENT function my_name is called, the child first_name is also being called. We are then returning back the function first_name as the value.


Now that the pre-requisites for decorators are complete, let's take a look at the glorious Python Decorators.

To Recall,

A decorator is a function that takes another function and adds some functionality to it, without modifying it.

To demystify, let us make a sandwich. Uhm.., Yes, You heard it right. A VEGETABLE SANDWICH!!

Cooking Class 101 - How to make a vegetable sandwich!๐Ÿฅช

Sandwich.gif

We will take some veggies, cut them in same size, arrange them neatly on top of bread, add some cheese slices and add another bread at the top of cheese slices.

Note: Here we are just adding layers as per our taste. We are not changing any function of the individual elements.

Pretty Easy right. The same with Decorators. You take a function, add some layers to it without modifying the original function or structure. Now, take a look at the below code.

#Decorator Declaration
def my_decorator(func):
  def wrapper():
    print "Before Function call"
    func()
    print "After Function call"
     return wrapper

#Function Declaration
def my_name():
  print("My name is Python")


#Function call
my_name = my_decorator(my_name)
my_name()

Code Explanation:

  1. Take a look at the first part - Decorator Declaration

It is nothing but a function which has an inner function - wrapper() within it.

  1. Now Second part - Function Declaration

This is where we declare our main function, to which you need to add extra layers to extend its functionality.

  1. Now the Last part - Function call

Here, we are assigning the function to the decorator and calling the decorator function with the function my_name as its argument.

In the above code, wrapper is the part where we have to concentrate. It is where the layers are getting added.

  • As the name implies, the decorator takes the function my_name as it argument.

  • It executes it's inner function wrapper, which will print the statement - "Before Function call"

  • Then, the func() will call the original function my_name, which prints - "My name is Python"

  • Again it executes the last statement - "After Function call" before returning the wrapper.

Output:

Before Function call
My name is Python
After Function call

If the above explanation is still confusing, let us take a look at another exampleโฌ‡๏ธ

20KMhr.gif

You are planning to go out on a bright day. Suddenly, wind of 25 km/hr blows. What would you do? Add a sweater and carry on your work. But, then again, it rains. It is really turning into a bad day, isn't it? We would take an umbrella or wear a rain coat and carry on our work, because LIFE GOES ON!!๐Ÿฅด

Whatever the situation, we would simply wrap ourselves with some function. That is decorator. It may be a sweater or a rain coat. Doesn't matter.


Syntactic Sugar:

The python decorators can be simplified by using the Syntactic Sugar - @ symbol, called as PIE Syntax

Instead of assigning the decorator to the variable my_name and function, we can simply use @ to call the decorator.

#Decorator Declaration
def my_decorator(func):
  def wrapper():
    print "Before Function call"
    func()
    print "After Function call"
     return wrapper

#Function Declaration - Applying decorator using @ syntax

@my_decorator
def my_name():
  print("My name is Python")

#Function call
my_name()

So far, we have been looking about decorators, but why use them in the first place? Why can't we simply use functions instead?

That is a very good question.

Some of the Advantages of Decorators include,

  • can be reused anywhere in the program.

  • Decorators can accept arguments, however wrapper function should use positional and keyword arguments (args, *kwargs).

  • Decorators can return values.

And most importantly, if you are someone who is planning to learn Web development with FLASK (Python), decorators will be used in the program like many times. Therefore, it is safe to learn it beforehand.


That's all I have for you guys in this blogpost. Thank you for making it so far. Take care and I will see you soon with another blogpost!!๐Ÿ’™

Also, Check out my Blog website, made using Flaskโค๏ธ

I am on Twitter too!!

good-bye-peace-out.gif

ย