Python Decorators

In Python, a decorator is a function that takes another function as an argument and extends or alters its behavior. This allows us to "decorate" or modify the function without changing its actual code. Decorators are commonly used for logging, access control, memoization, and more.

What is a Decorator?

A decorator is a function that wraps another function. The idea behind decorators is to enable adding functionality to an existing function without modifying its structure. This is a powerful feature in Python and is commonly used in frameworks and libraries, such as Flask and Django, to add behavior to functions and methods.

Think of decorators as a way to modify or enhance a function in a clean and reusable way. They allow us to keep the code modular by separating concerns and improving the maintainability of the code.

How Decorators Work?

A decorator is a function that takes a function as its argument and returns a new function that enhances or modifies the original function's behavior. Here's the basic syntax:

Syntax


def decorator_function(original_function):
    def wrapper_function():
        print("Wrapper executed this before {}".format(original_function.__name__))
        return original_function()
    return wrapper_function
        

In the example above: - decorator_function takes the original function as an argument. - Inside the decorator, another function called wrapper_function is defined. The wrapper function adds behavior before calling the original function. - The decorator function returns the wrapper_function.

Code Example of a Basic Decorator:


def decorator_function(original_function):
    def wrapper_function():
        print("Wrapper executed this before {}".format(original_function.__name__))
        return original_function()
    return wrapper_function

def display():
    return "Display function executed!"

# Decorating the display function
decorated_display = decorator_function(display)
print(decorated_display())
            

Explanation of the Code:

- decorator_function takes a function (display) as an argument. - Inside the decorator, wrapper_function is called, which adds behavior (printing a message) before calling the original function. - The decorator_function returns the wrapper_function, effectively replacing the original function with the decorated one. - The output of the code will show that the wrapper function is executed before the original function.

Output

Wrapper executed this before display Display function executed!

Using Python's Built-in Decorators

Python also provides several built-in decorators like @staticmethod, @classmethod, and @property. These decorators are widely used in object-oriented programming (OOP) to modify the behavior of methods in classes.

Example of @staticmethod Decorator:

The @staticmethod decorator is used to define a method that doesn't need access to the instance of the class (i.e., it doesn't take self as the first argument). This method can be called on the class itself, rather than on an instance of the class.


class MyClass:
    @staticmethod
    def greet():
        return "Hello, static method!"

# Calling the static method
print(MyClass.greet())
            

Explanation of the Code:

- The @staticmethod decorator is applied to the greet method. - This method can be called directly on the class, without needing to create an instance. - Output will show the greeting message without needing to instantiate the class.

Output

Hello, static method!

Chaining Decorators

In Python, you can apply multiple decorators to a single function. These decorators are applied in the order from bottom to top. Here's an example of how you can chain multiple decorators:


def decorator_one(func):
    def wrapper():
        print("Decorator One executed!")
        return func()
    return wrapper

def decorator_two(func):
    def wrapper():
        print("Decorator Two executed!")
        return func()
    return wrapper

@decorator_one
@decorator_two
def hello():
    return "Hello, world!"

# Calling the function with chained decorators
print(hello())
            

Explanation of the Code:

- We define two decorators: decorator_one and decorator_two. - The @decorator_one decorator is applied first, followed by the @decorator_two decorator. - When the function hello() is called, both decorators are executed in the order from bottom to top, meaning decorator_two runs first, followed by decorator_one.

Output

Decorator One executed! Decorator Two executed! Hello, world!

Decorators are a powerful feature in Python that allows you to modify or extend the behavior of functions or methods without altering their code. They enable code reusability, cleaner syntax, and separation of concerns. By using decorators, you can add functionalities like logging, authorization, caching, etc., to your functions or classes in a clean and modular way.