What You Should Know About Python Decorators And Metaclasses

Learn the basic difference between Decorators and Metaclasses in Python.



What You Should Know About Python Decorators And Metaclasses
Image by Author

 

What are Python Decorators?

 

After hearing the word decorators, most of you probably guess it is something used for decoration. You guessed it right. At festivals like Christmas or new year, we decorate our houses using various lights and materials. But in python, the decorators are used to modify or enhance the functionality of python functions or methods.

Decorators are functions that wrap around the original function and add some additional functionalities without directly modifying the original code.

For example, imagine you are an owner of a bakery and an expert in making cakes. You make different cakes like Chocolate, Strawberry, and Pineapple. All cakes are made from different ingredients, but some steps are common to all cakes, like preparing the baking pan, pre-heating the oven, baking the cake, or removing the cake from the oven. So, we can make a common decorator function to perform all the common steps, make separate functions for different types of cakes, and use the decorators to add common functionality to these functions.

Consider the below code.

def common_steps(func):
    def wrapper():
        print("Preparing baking pans...")
        print("Pre-heating the oven...")
        result = func()
        print("Baking the cake...")
        print("Removing the cake from the oven...")
        return result

    return wrapper


@common_steps
def chocolate_cake():
    print("Mixing the chocolate...")
    return "Chocolate cake is ready!"


@common_steps
def strawberry_cake():
    print("Mixing the strawberries...")
    return "Strawberry cake is ready!"


@common_steps
def pineapple_cake():
    print("Mixing the pineapples...")
    return "Pineapple cake is ready!"


print(pineapple_cake())

 

Output:

Preparing baking pans...
Pre-heating the oven...
Mixing the pineapples...
Baking the cake...
Removing the cake from the oven...
Pineapple cake is ready!

 

The function comman_steps is defined as a decorator and contains all the common steps like baking or pre-heating. And the functions chocolate_cake, strawberry_cake, and pineapple_cake are defined, which contain different steps for different types of cakes.

Decorators are defined using the @ symbol, followed by the name of the decorator function.

Whenever a function is defined with a decorator, the original function is called with the decorator, and the decorator function returns a new function that replaces the original function.

The new function performs the additional functionalities before and after calling the original function.

Instead of the @ symbol, you can define the decorators in another way that provides the same results. E.g.,

def pineapple_cake():
    print("Mixing the pineapples...")
    return "Pineapple cake is ready!"


pineapple_cake = common_steps(pineapple_cake)

print(pineapple_cake())

 

Benefits of using Decorators:

 

  1. You can use the same code repeatedly without redundancy and avoid DRY (Don’t Repeat Yourself) principle.
  2. This makes your code more readable and easier to maintain.
  3. You can keep your code organized and clear, which helps you with concerns like Input Validation, Error Handling, or Optimization issues.
  4. Using decorators, you can add new functionalities to the existing functions or classes without modifying the code. This allows you to extend the code according to your business requirements.

 

What are Metaclasses?

 

It is the class of a class and defines how a class can behave. A class is itself an instance of a metaclass.

Before understanding the definition of a metaclass, first, understand the basic definition of python class and objects. Class is like a constructor that is used to create objects. We are creating classes to create objects. Objects are also known as the instance of a class used to access the class's attributes. Attributes can be any datatype like an integer, string, tuple, list, function, or even a class. So to use these attributes, we have to create instances (objects) in the class, and the method to create these instances is known as instantiation.

Everything in python is treated as an object. Even a class is also treated like an object. That means a class is instantiated from a different class. The class from which all the other classes are instantiated is known as a metaclass. The class defines the behavior of an object it belongs to. In the same way, the behavior of the class is defined by its metaclass, which is a Type class by default. In simpler terms, all classes are instances of a metaclass in python.

 

What is a Type Class?

 

In python, the Type class is the metaclass for all classes.  Every time you define a new class, by default, it is instantiated from the Type class unless you define another metaclass.

Type class is also responsible for the dynamic creation of python classes. When we define a new class, python sends the class definition to the type class, and then this class creates a new class object according to the class definition.

Let us consider an example.

class College:
    pass


obj = College()
print(type(obj))
print(type(College))

 

Output:

<class '__main__.College>
<class 'type'>

 

A new class named College is created, and an object obj of that class is instantiated. But when we print the object type, it outputs as <class '__main__.College>, which means that a particular object is created from the College class. But on the other hand, when we print the type of the College class, it outputs as <class 'type'>, which means that this class is created from the type class (metaclass) by default.

We can also change the default metaclass of these user-defined classes. Consider the below example.

class College(type):
    pass


class Student(metaclass=College):
    pass


print(type(Student))
print(type(College))

 

Output:

<class '__main__.College'>
<class 'type'>

 

When we print the type of the Student class, it refers to the College as a metaclass, but when we print the type of the College class, it refers to the type class as a metaclass. So this forms a hierarchy, as shown below.

 

What You Should Know About Python Decorators And Metaclasses
Image by Author
 

We can also use type class for the dynamic creation of new classes. Let us understand this more by the below example.

# This is the basic way of defining a class.
class MyClass:
    pass


# Dynamic creation of classes.
myclass = type("MyClass", (), {})

 

Both ways of defining the classes are equivalent. The type() function is used in this example to create a new class. It takes three arguments. The first argument takes the class name, the second is a tuple of the parent classes (empty in this case), and the third argument is a dictionary that takes the attributes of that class (also empty in this case).

Consider another example which is using the inheritance concept.

College = type("College", (), {"clgName": "MIT University"})
Student = type("Student", (College,), {"stuName": "Kevin Peterson"})
obj = Student()
print(obj.stuName, "-", obj.clgName)

 

Output:

Kevin Peterson - MIT University

 

A class named College is created having the argument clgName as MIT University. Another class Student is created, inherited from the College class, and an attribute stuName as Kevin Peterson is created.

When we create an object of the `Student` class, we can see that it can access the attributes of both classes. It means that the inheritance works perfectly in this example.

 

Conclusion

 

In this article, we have discussed Decorators and Metaclasses in python. Both metaclass and decorators modify the behavior of classes and functions but operate using different mechanisms.

Metaclasses operate at the lower level and allow you to change the structure or behavior of the class, like the class methods, attributes, and inheritance. Decorators, however, are used to modify the functions' behavior. They allowed you to add functionality to the existing functions without changing the code. Decorators operate at a higher level as compared to metaclasses. That’s why they are somewhat easier to understand and less complex than metaclasses.

 

What You Should Know About Python Decorators And Metaclasses
Difference between Metaclass & Decorators | Image by Author
 

It is all for today. I hope you have enjoyed reading this article. If you have any comments or suggestions, please get in touch with me via Linkedin.

 
 
Aryan Garg is a B.Tech. Electrical Engineering student, currently in the final year of his undergrad. His interest lies in the field of Web Development and Machine Learning. He have pursued this interest and am eager to work more in these directions.