BlogsDope image BlogsDope

Important Python Decorators

Dec. 15, 2020 PYTHON DECORATOR 195

A decorator is a function that takes another function as its argument and extends its functionality without changing its source code. In this tutorial, we are going to discuss some important built-in Python decorators such as @property, @classmethod, and @staticmethod. If you do not have basic knowledge of decorators, first study them here.

So, without further ado, let’s get started.

The @property decorator


The @property decorator is a built-in Python decorator that is used for the property() function. Let’s take an example of a Student class to understand how and why to use this decorator.

Let’s say we have a Student class having properties, first name, last name, and score. This class also contains a method that returns the full name of the student. Let’s see.

class Student:
    def __init__(self, first, last, score):
        self.first = first
        self.last = last
        self.score = score

    def full_name(self):
        return self.first + " " + self.last


std = Student("ashton", "agar", 98)
std.full_name()

Output

​ashton agar

Now, let’s say we want to add a feature in which the user can directly change their full name, and when they change it, their first name and last name get updated as well. 

One way of doing this is to create a different method, which updates the value of first and last names. Since we are creating a new setter method and for readability purpose, we change the name of full_name() to get_full_name() to have consistency in the code, i.e.,

class Student:
    def __init__(self, first, last, score):
        self.first = first
        self.last = last
        self.score = score

    def get_full_name(self):
        return self.first + " " + self.last

    def set_full_name(self, fullname):
        first, last = fullname.split(" ")
        self.first = first
        self.last = last


std = Student("ashton", "agar", 98)
std.set_full_name("ashton turner")
std.get_full_name()

Output

​ashton turner

Each time we want to change the full name or retrieve it, we need to use different methods. Instead of doing this, we can use the property() method to implicitly call the setters, getters, and deleters. It returns an object of the property class. Let’s see.

class Student:
    def __init__(self, first, last, score):
        self.first = first
        self.last = last
        self.score = score

    def get_full_name(self):
        return self.first + " " + self.last

    def set_full_name(self, fullname):
        first, last = fullname.split(" ")
        self.first = first
        self.last = last

    full_name = property(get_full_name, set_full_name)


std = Student("ashton", "agar", 98)
std.full_name = "ashton turner"
print(std.full_name)

Output

​ashton turner

Instead of using the property() method, a better way is to use the @property decorator. It is more readable and convenient to use. Let’s see.

class Student:
  def __init__(self, first, last, score):
    self.first = first
    self.last = last
    self.score = score
  
  @property
  def full_name(self):
    return self.first + " " +self.last
  
  
  @full_name.setter
  def full_name(self, fullname):
    first, last = fullname.split(" ")
    self.first = first;
    self.last = last

  @full_name.deleter
  def full_name(self):
    del self.first
    del self.last

std = Student("ashton", "agar", 98)
print(std.full_name)
std.full_name = "ashton turner"
print(std.full_name)
print(std.first, std.last)

Output

​ashton agar
ashton turner
ashton turner

The @property decorator allows us to use full_name as a property now. Therefore, we can retrieve it without the parenthesis.

The @full_name.setter indicates that it is a setter method for the full_name property. Using this, you can update the value like you would for any property.

We can also delete the property of that instant using @full_name.deleter. Let’s see.

del std.full_name
print(std.full_name)

Output

In the deleter method, we delete the first and last names. Therefore, when we try to call the full name after deleting it, we get an error.

The @classmethod decorator


A regular method in a class, or more specifically an instance method, is a method that is bound to the object instance. It takes an implicit parameter self, which points to the object instance that invoked it. A class method, however, is bound to the class. It takes an implicit pointer to its class as its parameter. By convention, we denote it by cls. To create a class method, use the @classmethod decorator. Class methods are often used as alternative constructors or as factory methods.

The @staticmethod decorator


The static method, on the other hand, does not take an object instance or a class, which means that it can’t access their states. It is also bound to its class. The @staticmethod decorator creates a static method. They are used to make helper or utility functions. These methods have a logical connection with the class but do not use class or object state.

Example of @classmethod and @staticmethod


Let’s take an example to understand both. We create a Student class, which contains properties: first name and last name. However, a user can directly instantiate an object using the full name as well. We will implement it by using the class method as an alternative constructor. Moreover, we have a static method scholarship() that takes a GPA and tells whether a student is eligible for a scholarship or not. This method does not use either class or object state but has a logical connection with the class.

class Student:
    def __init__(self, first, last):
        self.first = first
        self.last = last

    def display_info(self):
        print(f"The name of the student is {self.first} {self.last}")

    @classmethod
    def from_string(cls, fullname):
        first, last = fullname.split(" ")
        return cls(first, last)

    @staticmethod
    def scholarship(gpa):
        if gpa >= 3.8 and gpa <= 4.0:
            print("eligible for scholarship")
        else:
            print("Not eligible")


# using the default constructor to create a Student instance
std1 = Student("Ashton", "Agar")
std1.display_info()

# using the alternatice constructor to create a Student instance
std2 = Student.from_string("Karen Hill")
std2.display_info()

# using the static method
Student.scholarship(3.9)
Student.scholarship(3.4)

Output

​The name of the student is Ashton Agar
The name of the student is Karen Hill
eligible for scholarship
Not eligible

You can invoke the class method and static method with either the object instance or the class itself.


Liked the post?
A computer science student having interest in web development. Well versed in Object Oriented Concepts, and its implementation in various projects. Strong grasp of various data structures and algorithms. Excellent problem solving skills.
Editor's Picks
0 COMMENT

Please login to view or add comment(s).