Coders Packet

Decorators in Python

By Aditya Vilas Dorge

Imagine working on a large project consisting of tens of thousands of lines of code which may includes multiple functions and classes. Continuous modification in the code could be problematic .

There is when decorators come into picture.

What are decorators?
Decorators helps to add new functionality to an existing function without modifying it.

Suppose you are creating a program in Python that greets the customer and makes ice-cream for them , bad you can’t eat it :) 

Program would look like:

def greet_n_icecream():
  print(" Welcome, would you like to have an ice-cream? ")
  print(" Making ice-cream ")

This is a simple Python function which just prints “Welcome, would you like to have an ice-cream?” and “Making ice-cream” but what if we need different function which does these activities separately.

Program would look like:

def greeting():
  print("Welcome, would you like to have an ice-cream?")
def icecream():
  print("Making ice-cream")

But due to this we have to modify both the programs separately, isn’t is cumbersome?
This is when decorators come to rescue.

Types of decorators

There are two types of decorators: function decorators and class decorators.

Lets take a look at both of them:

1) Function decorators: Here decorator is a function.

Syntax:

def decorator(func):
  “Do something”

@decorator
def function():
  “Do something”
function()

Code:

def my_decorator(func):
  def inner():
    print("Welcome , would you like to have an ice-cream ?")
    func()
    print("Thank-you , Come again")	
  return inner

def icecream():
  print("Making ice-cream")

icecream = my_decorator(icecream)
icecream()

Output:

Welcome, would you like to have an ice-cream ?
Making ice-cream
Thank-you, Come again

Let us understand line by line what is happening .

At line my_decorator(func)we create decorator function called my_decorator which takes a function as a parameter.

At line def inner()we create another function inside the my_decorator .

The purpose of having a inner function is that a function decorator receives a function object to decorate, and it must return the decorated function.

At line func()we call the icecream() using func().

At line return innerwe return the decorated objects adding new functionality.

At line def icecream()we have our icecream function which prints “Making ice-cream” .

At line my_decorator(icecream)we call the my_decorator function passing icecream function as an argument .

It is equivalent to:

def my_decorator(func):
  def inner():
    print("Welcome , would you like to have an ice-cream ?")
    func()
    print("Thank-you , Come again")	
  return inner
  
@my_decorator
def icecream():
  print("Making ice-cream")	
  
icecream()

The line @my_decorateraddresses the my_decorator().

Decorators with parameters

Code:

def my_decorator(func):
  def inner(*args,**kwargs):
    print("Welcome , we have following flavour of ice-cream:")
    for key ,  value in kwargs.items():
      print(value)
    func()
    print("Thank-you , Come again")	
  return inner
  
@my_decorator
def icecream():
  print("Making ice-cream")	
  
icecream(flavour1 = 'chocolate',  flavour2 = 'vanilla',flavour3 ='strawberry')

Output:

Welcome , we have following flavour of ice-cream:
chocolate
vanilla
strawberry
Making ice-cream
Thank-you , Come again

2) Class decorators: Similar to function decorators but the decorator here is a class . Class decorators are mainly used for updating the status of a program and adding additional extra key features to the program .

Syntax:

Class decorator:
  “Do something”

@decorator
def function():
  “Do something”
function()

Code:

class iceCreamDecorator:
  def __init__(self,func):
    self.func = func 
    self.order_count = 0
  
  def __call__(self):
    self.order_count+=1
    print("Welcome , would you like to have an ice-cream ?")
    self.func()
    print("Thank-you , Come again")
    print("Number of order served :" , self.order_count)

@iceCreamDecorator	
def icecream():
  print("Making ice-cream")

icecream()
icecream()

Output:

Welcome , would you like to have an ice-cream ?
Making ice-cream
Thank-you , Come again
Number of order served : 1
Welcome , would you like to have an ice-cream ?
Making ice-cream
Thank-you , Come again
Number of order served : 2

Lets understand the code line by line :

At line  class iceCreamDecorator we create a class decorator called iceCreamDecorator.

At line def __init__(self,func):we create a constructor which takes func (function) as an parameter .

At line def __call__(self):__call__ method is invoke every time the icecream function is called thereby printing the greeting and order status .

Decorators are an amazing tool in Python of greater importance . I highly recommend you to play around with decorators , find and learn various applications of it . Don’t forget to check out Python documentation for further details .

Download Complete Code

Comments

No comments yet