How to Use Decorators in Python Functions

Introduction

Python decorators are a powerful and expressive tool that allows you to modify the behavior of functions or classes. They provide a clean and readable way to extend or alter the functionality of functions and methods without modifying their actual code.

This guide shows you how to use decorators in Python functions.

Prerequisites

Before you begin:

  • Deploy a VPS server. For instance, Ubuntu 24.04.
  • Create a non-root sudo user.
  • Install Python.

Define a Basic Decorator

To define a basic decorator, you need to create a function that takes another function as an argument, and then define a wrapper function inside it that adds some functionality before or after calling the original function.

Here’s the basic syntax:

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

Example:

Python
def say_hello():
    print("Hello!")

say_hello = my_decorator(say_hello)

say_hello()
# Output:
# Something is happening before the function is called.
# Hello!
# Something is happening after the function is called.

In this example, the decorator my_decorator adds functionality before and after the say_hello function.

Use the @ Syntax for Decorators

To apply a decorator more conveniently, you can use the @ syntax. This syntax is placed above the function to be decorated.

Example:

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

say_hello()
# Output:
# Something is happening before the function is called.
# Hello!
# Something is happening after the function is called.

In this example, the @my_decorator syntax decorates the say_hello function.

Work with Function Arguments in Decorators

If the function you're decorating takes arguments, the wrapper function must accept those arguments and pass them to the original function.

Example:

Python
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Something is happening before the function is called.")
        result = func(*args, **kwargs)
        print("Something is happening after the function is called.")
        return result
    return wrapper

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

greet("Alice")
# Output:
# Something is happening before the function is called.
# Hello, Alice!
# Something is happening after the function is called.

In this example, the wrapper function takes *args and **kwargs to handle any number of positional and keyword arguments.

Chain Multiple Decorators

You can chain multiple decorators on a single function by stacking the @ syntax.

Example:

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

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

@decorator_one
@decorator_two
def say_hello():
    print("Hello!")

say_hello()
# Output:
# Decorator One
# Decorator Two
# Hello!

In this example, Python decorates the say_hello function with decorator_one and decorator_two.

Use Decorators with Classes

You can also use decorators with class methods. When doing so, you must account for the self parameter in the wrapper function.

Example:

Python
def my_decorator(func):
    def wrapper(self, *args, **kwargs):
        print("Something is happening before the method is called.")
        result = func(self, *args, **kwargs)
        print("Something is happening after the method is called.")
        return result
    return wrapper

class Greeter:
    @my_decorator
    def greet(self, name):
        print(f"Hello, {name}!")

greeter = Greeter()
greeter.greet("Alice")
# Output:
# Something is happening before the method is called.
# Hello, Alice!
# Something is happening after the method is called.

In this example, Python decorates the greet method of the Greeter class with my_decorator.

Conclusion

This guide explains how to use decorators in Python functions, including defining basic decorators, using the @ syntax, handling function arguments, chaining multiple decorators, and applying decorators to class methods. Decorators provide a powerful way to modify or extend the behavior of functions and methods in a clean and readable manner.