Python Decorators

Python Decorators

A decorator in Python is a design pattern that allows you to add new functionality to an existing object without modifying its structure. Decorators are usually called before the definition of a function you want to decorate.

In this tutorial, you’ll learn about the basics of decorators and how to create your own.

Understanding Decorators

A decorator is a function that takes another function as an argument, adds some kind of functionality, and then returns another function.

Here’s a simple example of a 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

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

say_hello()

When you run this code, you’ll see the following output:

Something is happening before the function is called.
Hello!
Something is happening after the function is called.

The @my_decorator syntax is just a shorter way of saying say_hello = my_decorator(say_hello).

Creating Your Own Decorators

To create a decorator, you just need to define a function that takes a function as an argument and returns another function.

Here’s an example of a decorator that logs the execution time of a function:

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Function {func.__name__} took {end_time - start_time:.4f} seconds to run.")
        return result
    return wrapper

@timer
def my_function(n):
    sum = 0
    for i in range(n):
        sum += i
    return sum

my_function(1000000)

In this example, the timer decorator takes a function as an argument and returns a wrapper function. The wrapper function records the start time, calls the original function, records the end time, and then prints the execution time.

The *args and **kwargs in the wrapper function are used to pass any arguments to the original function.

Decorators with Arguments

You can also create decorators that take arguments. Here’s an example of a decorator that repeats a function a certain number of times:

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 say_hello():
    print("Hello!")

say_hello()

This will print “Hello!” three times.

Common Use Cases for Decorators

Decorators are used for a variety of purposes in Python, including:

  • Logging: Logging the execution of a function.
  • Timing: Timing how long a function takes to run.
  • Caching: Caching the results of a function to improve performance.
  • Authentication: Checking if a user is authenticated before allowing them to access a function.
  • Validation: Validating the arguments of a function.

Conclusion

In this tutorial, you’ve learned about Python decorators and how to create your own. Decorators are a powerful tool that can help you to write more concise and reusable code.

For more information on decorators, you can refer to the official Python documentation: https://www.python.org/dev/peps/pep-0318/

Last updated on