In Python, a decorator allows us to wrap another function in order to extend the behavior of the wrapped function, without permanently modifying it. Decorators provide a simple syntax for calling higher-order functions.
In this post, I will provide some exercises and examples that illustrate the usage of decorators in Python. Let’s dive right in.
1. Basic decorator
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
def say_hello():
    print("Hello!")
say_hello = my_decorator(say_hello)
say_hello()
Output:

2. Using the @ symbol for decorators
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
@my_decorator
def say_hello():
    print("Hello!")
say_hello()
Output:

3. Decorating functions with arguments
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Something is happening before the function is called.")
        func(*args, **kwargs)
        print("Something is happening after the function is called.")
    return wrapper
@my_decorator
def greet(name):
    print(f"Hello {name}!")
greet("Pythonista Planet")
Output:

4. Returning values from decorated functions
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 add(x, y):
    return x + y
result = add(5, 10)
print(result)
Output:

5. Using multiple decorators on a single function
def decorator_1(func):
    def wrapper():
        print("Decorator 1")
        func()
    return wrapper
def decorator_2(func):
    def wrapper():
        print("Decorator 2")
        func()
    return wrapper
@decorator_1
@decorator_2
def greet():
    print("Hello!")
greet()
Output:

6. Class decorators
class MyDecorator:
    def __init__(self, func):
        self.func = func
    def __call__(self):
        print("Something is happening before the function is called.")
        self.func()
        print("Something is happening after the function is called.")
@MyDecorator
def greet():
    print("Hello!")
greet()
Output:

7. Decorators with arguments
def repeat(num_times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                func(*args, **kwargs)
        return wrapper
    return decorator
@repeat(3)
def greet(name):
    print(f"Hello {name}")
greet("Pythonista Planet")
Output:

8. Caching return values
import functools
@functools.lru_cache(maxsize=4)
def fibonacci(num):
    print(f"Calculating fibonacci({num})")
    if num < 2:
        return num
    return fibonacci(num - 1) + fibonacci(num - 2)
print(fibonacci(10))
Output:

9. Making a decorator with user-defined exception
def validate(func):
    def wrapper(*args):
        if len(args) > 0 and isinstance(args[0], int):
            if args[0] > 0:
                return func(*args)
        raise ValueError("Value must be a positive integer")
    return wrapper
@validate
def print_num(num):
    print(num)
print_num(10)
print_num(-1)
Output:

I hope that these examples would give you a good understanding of decorators in Python. Decorators can be a powerful tool, and while they might seem a bit confusing at first, with some practice, you’ll be able to use them effectively in your code.
Remember that they are simply functions that take a function and return a new function. This concept of functions returning functions is one of the cornerstones of functional programming and is part of what makes Python such a powerful and flexible language.
If you found this post useful, check out my post on 20 Python File I/O Exercises and Examples.
Recent Posts
Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules. In this tutorial, let's understand what modular...
While Flask provides the essentials to get a web application up and running, it doesn't force anything upon the developer. This means that many features aren't included in the core framework....

