Decorators in Python : Adding Functionalities to Functions

Decorator in Python is an important feature used to add functionalities to an existing function, object, or code without modifying its structure permanently. It allows you to wrap a function to another function and extend its behavior. Decorators in Python are usually called before the definition of the to-be decorated function.

Before going any further about decorators, it is essential to know more about functions. Functions in Python are first-class objects that support various operations. The properties of functions and other first-class objects can be:

  • Passed as an argument
  • Returned from a function
  • Modified
  • Assigned to other variables
  • Stored in data structures such as hash tables and lists

Python Training Course

Learn Data Operations in PythonExplore Course
Python Training Course

Syntax of Python Decorators

Since you now know a bit about functions and what decorators in Python do, it’s time to get acquainted with the syntax, which is:

def func_name():

    print("Simplilearn") #function code

func_name = name_decorator(func_name)

In the above syntax:

  • func_name: Name of the function
  • name_decorator: Name of the decorator

Python also provides a simpler syntax to write decorators in Python using @symbol and the decorator’s name. This simpler way of calling decorators is also called the syntactic way or the “pie” syntax. With the simpler syntax, the code is equal to -

@name_decorator

def func_name():

    print("Simplilearn")

The only difference in using both the syntax is that if you want to assign the decorated function to another variable of a function, use the extended syntax. On the other hand, if you’re going to change the same function’s variables and content, you can use both the long and short syntax.

Example of Decorators in Python

Let’s look at an example to better understand the concept of decorators in Python. In the example below, you will create a decorator to add the functionality of converting a string from another function to the uppercase.

#defining the decorator

def name_decorator(function):

    #defining the wrapper function

    def inner_wrapper():

        #defining and calling the actual function

        func_name = function()

        uppercase_func = func_name.upper()

        print (uppercase_func)

    return inner_wrapper

#defining the function that will be called in decorator

def greet():

    return ("welcome to simplilearn")

    print (greet())

decorated = name_decorator(greet)

decorated()

print (greet())

Output:

DecoratorsinPython_1

In the example above, name_decorator() is the decorator. The function ‘greet’ got decorated and was assigned to “decorated.” As you can see, when you print the decorated function, it prints the string in uppercase. However, when you call the greet function again, it prints the exact string in the lowercase. Thus, the greet function is not changed permanently.

Decorators in Python With Parameters

In the example above, you worked with a function that did not have any parameters. But what if the function has parameters? Let’s have a look.

def arguments_decorator(function):

    def wrapper_arguments(ar1, ar2):

        print("Arguments passed are: {0}, {1}".format(ar1,ar2))

        function(ar1, ar2)

    return wrapper_arguments

@arguments_decorator

def Name(first_name, last_name):

    print("My Name is {0} {1}".format(first_name, last_name))

Name("George", "Hotz")

Output:

DecoratorsinPython_2

How to Reuse Decorators in Python?

Since a decorator is also like a normal function, you can easily reuse it like the others by moving it to the ‘decorators’ module. In the code below, you will create a file named “decorators.py.” The file will contain a decorator function that will print an output multiple times. Next, you will import the decorator function in the main coding file and reuse it.

# code for decorators.py file

def print_thrice(func):

    def wrapper_print_thrice():

        func()

        func()

        func()

    return wrapper_print_thrice

# code for main.py file

from decorators import print_thrice

@print_thrice

def say_name():

    print("Simplilearn!")

say_name()

Output:

DecoratorsinPython_3

As you can see in the output stated above, you could import and reuse the print_thrice decorator function to print the output “Simplilearn!” three times.

Chaining Multiple Decorators in Python

It is possible to chain numerous decorators in Python. It is like applying multiple decorators to a single function. All you have to do is to place all the decorators in separate lines before defining the wrapper function. Here’s an example of a chaining decorator in Python.

def exclamation_decorator(function):

    def wrapper(*args, **kwargs):

        print("!" * 25)

        function(*args, **kwargs)

        print("!" * 25)

    return wrapper

def hashtag_decorator(function):

    def wrapper(*args, **kwargs):

        print("#" * 25)

        function(*args, **kwargs)

        print("#" * 25)

    return wrapper

@exclamation_decorator

@hashtag_decorator

def message(greet):

    print(greet)

message("Welcome to Simplilearn")

Output:

DecoratorsinPython_4

FREE Data Science With Python Course

Start Learning Data Science with Python for FREEStart Learning
FREE Data Science With Python Course

Defining the General Purpose Decorators in Python

If you noticed, we used *args and **kwargs in the previous example. These variables help define general-purpose decorators in Python. They will collect all the positional and keyword arguments that you pass, and store them in the args and kwargs variables, respectively. These variables allow you to give as many arguments as you want while calling the function, thereby making it general. Here’s an example of general-purpose decorators in Python.

def general_purpose_decorator(function):

    def a_wrapper(*args,**kwargs):

        print('Positional arguments:', args)

        print('Keyword arguments:', kwargs)

        function(*args)

    return a_wrapper

@general_purpose_decorator

def no_argument():

    print("There are no arguments.")

no_argument()

@general_purpose_decorator

def positional_arguments(a, b, c):

    print("These are positional arguments")

positional_arguments(1,2,3)

@general_purpose_decorator

def keyword_arguments():

    print("These are keyword arguments")

keyword_arguments(city1_name="Mumbai", city2_name="Delhi")

Output:

DecoratorsinPython_5.

In the example above, you defined a general-purpose decorator in Python. You also passed the positional and keyword arguments separately with different functions.

Working With Some Fancy Decorators in Python

The examples you have seen until now are pretty basic ones to get you acquainted with the concept of decorators. But now, since you have a basic understanding, let’s look at some advanced decorator functions.

Example: Using Stateful Decorators in Python

Stateful decorators are the decorator function that can keep the track of state, or in other words, remember their previous run’s state. In the code below, you have to create a stateful decorator to decorate a dictionary that can store the number of times the function is called.

import functools

def count_calls(func):

    @functools.wraps(func)

    def wrapper_count_calls(*args, **kwargs):

        wrapper_count_calls.num_calls += 1

        print(f"Call {wrapper_count_calls.num_calls} of {func.__name__!r}")

        return func(*args, **kwargs)

    wrapper_count_calls.num_calls = 0

    return wrapper_count_calls

@count_calls

def say_whee():

    print("Whee!")

Output:

DecoratorsinPython_6

Example: Using Classes as Decorators in Python

Although you can use functions to track the state, the typical way is by using a class. Similar to the previous example, you will create a decorator function to maintain the state of a function. But this time the decorator function will be a class. You will have to call .__inti__ and() .__call__() methods to initialize and call the class instance, respectively. Note that the .__call__() method will be called in this example instead of the decorator function. It will act as the wrapper function that you have been using until now.

from functools import update_wrapper

class example:

    def __init__(self, func):

        update_wrapper(self, func)

        self.func = func

        self.example = {}

        self.n_calls = 0

    def __call__(self, *args, **kwargs):

        self.n_calls += 1

        self.example[self.func.__name__] = self.n_calls

        print("The count is :", self.example)

        return self.func(*args, **kwargs)

@example

def hi(name):

    return f"Hi {name}!"

print(hi("Simplilearn"))

print(hi("George"))

print(hi("Amit"))

Output:

DecoratorsinPython_7

As you can see in the output, you have used a class as a decorator to track the state of the hi() function.

What is the Decorators Library in Python?

The Python Decorators Library serves as a repository of numerous decorators’ codes and examples. You can refer to, use, or tweak them according to your wish. You can also add your decorators to this repository to help others learn. It is a great resource to learn about decorators in Python in-depth with many examples. You can refer to the Decorator Library by clicking here.

Looking forward to making a move to the programming field? Take up the Python Training Course and begin your career as a professional Python programmer

Summing It Up

In this article, you have learned the A to Z of decorators in Python, right from how to create them to the different ways to use them. However, it is an advanced topic. Hence, it is recommended to get a firm understanding of Python basics before delving deep into decorators.

You can refer to Simplilearn’s Python Tutorial for Beginners to clear the basics first. Once your basics are clear, you can move ahead by going into the advanced topics. You can excel in Python programming by further opting for our Online Python Certification Course. The course comes with 38 hours of blended learning, 30 hours of instructor-led learning, and 20+ assisted practices on modules to help you excel in Python development.

Have any questions for us? Leave them in the comments section of this article. Our experts will get back to you on the same, ASAP!

About the Author

SimplilearnSimplilearn

Simplilearn is one of the world’s leading providers of online training for Digital Marketing, Cloud Computing, Project Management, Data Science, IT, Software Development, and many other emerging technologies.

View More
  • Disclaimer
  • PMP, PMI, PMBOK, CAPM, PgMP, PfMP, ACP, PBA, RMP, SP, and OPM3 are registered marks of the Project Management Institute, Inc.