A Beginner’s Guide to Python Decorators With Examples

Python decorators are robust and flexible features that enable you to modify the behaviors of the methods, functions, and classes without changing their source code.

They offer a clean way of adding functionality to the existing code by wrapping it with additional logic.

In Today’s guide, we will discuss Python decorators, their working, usage, the method to use decorators with arguments, chaining and stacking decorators, and the creation of custom decorators. So, let’s get started!

What are Decorators in Python

As a Python programmer, decorators permit you to improve or change the behavior of methods, and functions, without changing their actual code.

You can utilize >decorators in different scenarios, such as input validation, logging, and code profiling.

Additionally, decorators use functions as their first-class objects and provide an efficient way for adding functionality to existing functions.

How Does Decorator Work in Python

Talking about working, a decorator is a function that accepts another function as an argument. It extends its behavior without altering it explicitly. This can be achieved by using the “@decorator_name” syntax above the function that needs to be decorated.

When the decorated function is invoked, it is actually replaced by the decorator function. More specifically, this concept is known as function wrapping.

For instance, we will first define a simple decorator “my_decorator()” that adds some behavior before and after the decorated function “say_hello()” is invoked.

Here, the “@my_decorator” syntax applies to the decorator the “say_hello()” function.

When we invoke the “say_hello()” function, it is wrapped by the “my_decorator()” function which will ultimately print the additional output.

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is invoked.")
        func()
        print("Something is happening after the function is invoked.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()
How Does Decorator Work in Python
How Does Decorator Work in Python

How to Create and Apply Decorators in Python

As discussed above, the “@decorator_name” syntax can be added above the function definition. In this way, you can also chain decorators, which permits multiple layers of functionality to be added.

In the below example, we will create a decorator named “uppercase_decorator()” that transforms the result of the “say_hello()” decorated function into uppercase.

When we will invoke the “say_hello()” method with the “User” as an argument. Then, the decorator updates the output string in the uppercase.

def uppercase_decorator(func):
    def wrapper(text):
        result = func(text)
        return result.upper()
    return wrapper

@uppercase_decorator
def say_hello(name):
    return f"Hello, {name}!"

print(say_hello("User"))
Create and Apply Decorators in Python
Create and Apply Decorators in Python

Using Python Decorators

Python decorators can be utilized for logging function calls, caching results, measuring execution time, access control, and more. They offer a modular way of improving the functionality of the function without miss-arranging the relevant code.

Here, we will define a “log_decorator()” function that logs the function calls and outputs their values. When this log function will be applied to the “add()” function with the “@” syntax.

def log_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"Calling function: {func.__name__}")
        result = func(*args, **kwargs)
        print(f"{func.__name__} returned: {result}")
        return result
    return wrapper

@log_decorator
def add(a, b):
    return a + b

result = add(3, 5)

The decorator logs information before and after the function execution which ultimately provides insights into the behavior of the function.

Using Python Decorators
Using Python Decorators

Python Decorators with Arguments

Decorators can accept arguments that permit them to be more customizable and flexible. This enables the decorators to adapt their behavior based on the input arguments.

According to the provided code, the “repeat()” decorator accepts an argument “n” and creates a decorator that repeats the decorated function’s execution “n” times.

More specifically, passing “3” as the “@repeat()” decorator function argument applies the decorator to the “greet()” function.

def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

greet("User")

Consequently, the specified greeting will be displayed three times on the console.

Python Decorators with Arguments
Python Decorators with Arguments

Chaining and Stacking Decorators

Decorators can be combined by stacking them by utilizing the “@” syntax. This chaining permits multiple decorators to alter the behavior of a function in a sequential manner.

For instance, we have two decorates named “upper_decorator()” and “exclamation_decorator()“. So when these decorators are applied to the “say_hello()” function in the given sequence, the decorators will modify the behavior of the function.

def uppercase_decorator(func):
    def wrapper(text):
        result = func(text)
        return result.upper()
    return wrapper

def exclamation_decorator(func):
    def wrapper(text):
        result = func(text)
        return f"{result}!"
    return wrapper

@exclamation_decorator
@uppercase_decorator
def say_hello(name):
    return f"Hello, {name}."

greeting = say_hello("GeeksVeda User")
print(greeting)

It can be observed that the greeting message has been shown in uppercase with an exclamation mark.

Chaining and Stacking Decorators
Chaining and Stacking Decorators

Decorators for Class Methods and Properties

Decorators are not only restricted to functions. They can be also utilized with the class methods and properties. This enables you to alter the behavior of the properties and methods within the classes. Additionally, this offers additional control and customization.

Here, the “upper_property()” decorator has been applied to the “full_name” property of the “Person” class. This decorator then converts the property’s value to uppercase when accessed.

def uppercase_property(func):
    return property(lambda self: func(self).upper())

class Person:
    def __init__(self, first_name, last_name):
        self._first_name = first_name
        self._last_name = last_name

    @uppercase_property
    def full_name(self):
        return f"{self._first_name} {self._last_name}"

person = Person("Sharqa", "Hameed")
print(person.full_name)
Decorators for Class Methods and Properties
Decorators for Class Methods and Properties

How to Create Custom Decorators

In Python, you are also permitted to create customized decorators for addressing specific requirements or implementing reusable behavior. They offer a way for encapsulating logic that can be applied to multiple functions, classes, or methods.

For instance, we will define a “captilize_decorator()” that capitalizes the first letter of the resultant values returned by a function. This custom decorator will be then applied to both the “greet()” and “introduce()” functions.

def capitalize_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result.capitalize()
    return wrapper

@capitalize_decorator
def greet(name):
    return f"hello, {name}"

@capitalize_decorator
def introduce(name, age):
    return f"my name is {name} and I am {age} years old"

greeting = greet("GeeksVeda User")
print(greeting)
intro = introduce("Sharqa Hameed", 25)
print(intro)
How to Create Custom Decorators
How to Create Custom Decorators

That’s all from this effective guide related to Python decorators.

Conclusion

In Python programming, decorators enable you to create reusable and modular code. You can utilize it to improve the readability of your code. More specifically, Python decorators allow you to create and enhance the code functionality and also maintain simplicity.

Therefore, in this guide, we have explained this concept in detail.

Want to explore and learn more related to Python, do check out our dedicated Python Tutorial Series!

If you read this far, tweet to the author to show them you care. Tweet a thanks
As a professional content writer with 3 years of experience, I specialize in creating high-quality, SEO-optimized content that engages, attracts, and retains the audience.

Each tutorial at GeeksVeda is created by a team of experienced writers so that it meets our high-quality standards.

Join the GeeksVeda Weekly Newsletter (More Than 5,467 Programmers Have Subscribed)
Was this article helpful? Please add a comment to show your appreciation and support.

Got Something to Say? Join the Discussion...