top
upGrad KnowledgeHut SkillFest Sale!

Search

Python Tutorial

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 wrapperA '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(): passYou can now decorate this function to extend its behaviour by passing it to decoratordecorate=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  EvenAn 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(): passRewritten 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 decoratorLet 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.__priceThe property object’s getter and setter methods are also decorators. We define setter method as:       @price.setter        def price(self, x):                 self.__price=xThis 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=priceOutput:>>> from book import Book >>> b1=Book() >>> b1.price 40 >>> b1.price=50 >>> b1.price 50Class attributesRefer 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 decoratorInstance 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 decoratorThe 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():                passEven 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 decoratorJust 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
logo

Python Tutorial

Python - Decorators

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

Leave a Reply

Your email address will not be published. Required fields are marked *

Comments

Eula

This is my first time here. I am truly impressed to read all this in one place.

Jaypee Dela Cruz

Thank you for your wonderful codes and website, you helped me a lot especially in this socket module. Thank you again!

lucky verma

Thank you for taking the time to share your knowledge about using python to find the path! Your insight and guidance is greatly appreciated.

Pre Engineered Metal Building

Usually I by no means touch upon blogs however your article is so convincing that I by no means prevent myself to mention it here.

Pre Engineered Metal Building

Usually, I never touch upon blogs; however, your article is so convincing that I could not prevent myself from mentioning how nice it is written.

Suggested Tutorials

Swift Tutorial

Introduction to Swift Tutorial
Swift Tutorial

Introduction to Swift Tutorial

Read More

R Programming Tutorial

R Programming

C# Tutorial

C# is an object-oriented programming developed by Microsoft that uses the .Net Framework. It utilizes the Common Language Interface (CLI) that describes the executable code as well as the runtime environment. C# can be used for various applications such as web applications, distributed applications, database applications, window applications etc.For greater understanding of this tutorial, a basic knowledge of object-oriented languages such as C++, Java etc. would be beneficial.
C# Tutorial

C# is an object-oriented programming developed by Microsoft that uses ...

Read More