10X Sale
kh logo
All Courses
  1. Tutorials
  2. Programming Tutorials

Python - Decorators

Updated on Sep 3, 2025
 
39,063 Views

In Python, function is a first order object because it can be passed as argument to another function just as other data types such as number, string or list etc. It is also possible to define a function inside another function. Such a function that receives another function as argument is called 'decorator'. The behaviour of argument function is extended by the decorator without actually modifying it.

Decorator function is typically defined as follows:

def decorator(function):
       def wrapper():
               function()
       return wrapper

A 'function' is passed to decorator as argument. The decorator function returns 'wrapper' function which is defined in it. The wrapper calls the passed function and extends its functionality.

Here is a normal Python function:

def decorate():
pass

You can now decorate this function to extend its behaviour by passing it to decorator

decorate=adecorator(decorate)

If this function is now executed, it will show output extended by decorator.

#mydecorator.py
def decorator(function):
   def wrapper(num):
        print("Inside wrapper to check odd/even")
        if num%2 == 0:
            ret= "Even"
        else:
            ret= "Odd!"
        function(num)        
        return ret
   print ("wrapper function is called")
   return wrapper
#@my_decorator
def myfunction(x):
    print("The number is=",x)
myfunction=decorator(myfunction)
no=10
print ("It is ",myfunction(no))

The myfunction() just prints out the received number. However, its behaviour is modified by passing it to a decorator. The inner wrapper receives the number and returns whether it is odd/even.

Output:

wrapper function is called
Inside wrapper to check odd/even
The number is= 10
It is  Even

An elegant way to decorate a function is to mention just before its definition, the name of decorator prefixed by @ symbol. In this format a function() is defined as:

@decorator
def decorate():
pass

Rewritten version of above example mydecorator.py is as follows:

#mydecorator.py
def decorator(function):
   def wrapper(num):
        print("Inside wrapper to check odd/even")
        if num%2 == 0:
            ret= "Even"
        else:
            ret= "Odd!"
        function(num)        
        return ret
   print ("wrapper function is called")
   return wrapper
@decorator
def myfunction(x):
    print("The number is=",x)
no=10
print ("It is ",myfunction(no))

@property decorator

Let us return to definition of price property earlier in previous chapter.

price=property(getprice, setprice)

We shall now use built-in property() function as decorator to define price() as a getter method in book class:

@property
        def price(self):
              return self.__price

The property object’s getter and setter methods are also decorators. We define setter method as:

       @price.setter
       def price(self, x):
                self.__price=x

This eliminates need of defining getprice() and setprice() function. Rewritten book class is as below:

class Book:
   def __init__(self, price=40):
       self._price=price
   @property
   def price(self):
       return self._price
   @price.setter
   def price(self, price):
       self._price=price

Output:

>>> from book import Book
>>> b1=Book()
>>> b1.price
40
>>> b1.price=50
>>> b1.price
50

Class attributes

Refer to user.py example in previous chapter. In the User class name, email and role are called instance attributes. These attributes have different value for each object. Class attribute is one whose value is same for all instances of a class. Its value is shared by all objects. Class attribute is defined at class level outside __init__() method. Class attributes are accessed through name of class and not instance.

Let us add a class attribute 'counter' in User class. The __init__() method increments value of counter by 1 when each object is declared.

#user.py
class User:
       counter=0
       def __init__(self, name='Ram', email='ram@abc.com', role='Manager'):
               self.name=name
               self.email=email
               self.role=role
               User.counter=User.counter+1
               print ('Number of users created so far', User.counter)
       def display(self):
               print ('name:',self.name)
               print ('email:',self.email)
               print ('role:',self.role)

Note that counter attribute is referred to by name of class (User.counter) and not object. Let us import User class and create few objects.

>>> from user import User
>>> x=User()
Number of users created so far 1
>>> y=User('Raja','raja@xyz.com','guest')
Number of users created so far 2

@classmethod decorator

Instance methods receive object’s reference in the form of 'self'. The __init__() is an instance method. A method that is not by individual object but by the class is called class method. Python's built-in classmethod() is used as decorator to define such method in class. It has one argument 'cls' which refers to calling class. In the User class above, we shall add following class method called usercount().

 @classmethod
       def usercount(cls):
               print ("no of objects",cls.counter)

This method prints value of class attribute - counter. Obviously it doesn’t access attributes of any single object. Output of above script will now be as follows:

>>> from user import User
>>> x=User()
Number of users created so far 1
>>> y=User('abc', 'abc@xyz.xom', 'root')
Number of users created so far 2
>>> User.usercount()
no of objects 2

@staticmethod decorator

The staticmethod is also a built-in function in Python standard library. A Static method doesn’t receive any reference argument whether it is called by instance of class or class itself. Following notation used to declare a static method in a class:

class Myclass:
       @staticmethod
       def mymethod():
               pass

Even though Myclass.mymethod as well as Myclass().mymethod both are acceptable. Note that the static method doesn’t have any arguments – neither self nor cls.

Add following method in User class:

@staticmethod
       def countofusers():
               print("no. of objects",User.counter)

This method can be called by object or class as follows:

>>> from tmp import User
>>> x=User()
Number of users created so far 1
>>> y=User()
Number of users created so far 2
>>> z=User()
Number of users created so far 3
>>> User.countofusers()

Class decorator

Just as function is a callable object, class instance also is a callable object. A callable object is an object which can be used and behaves like a function but might not be a function. To define class in a way that its instances should be callable objects, it should have __call__ method. The instance is called "like a function", i.e. using brackets.

Class decorator contains a custom __class__() method. It returns a custom object that extends the functionality of what the original function does, in that case a class decorator should be used.

In following example add_decorator class has __call__ method. It modifies the arguments of decorated add() function. The add() function is designed to receive variable list of numbers. The decorator doubles those numbers before calling add() function.

class add_decorator:

   def __init__(self, f):
           self.f = f
   def __call__(self, *args):
               print ("original numbers:",args)
               # decorate add() before calling. doubles each number
               args=(2*i for i in args)
               self.f(*args)
               print ('decorator terminated')
               # after f actions
@add_decorator
def add(*args):
       print ("numbers received after decoration", args)
       s=0
       for n in args: s=s+n
       print ('addition of numbers',s)

Output:

>>> from adddecorator import add
>>> add(1,2)
original numbers: (1, 2)
numbers received after decoration (2, 4)
addition of numbers 6
decorator terminated
>>> add(10,20,30)
original numbers: (10, 20, 30)
numbers received after decoration (20, 40, 60)
addition of numbers 120
decorator terminated
+91

By Signing up, you agree to ourTerms & Conditionsand ourPrivacy and Policy

Get your free handbook for CSM!!
Recommended Courses