7) Decorators Lesson

Real Applications of Python Decorators

7 min to complete · By Martin Breuss

After writing a decorator function that displays information about the execution time of any of your functions, you've already seen a practical use of a decorator in the real world.

In this lesson, you'll learn about some additional common applications of decorators.

Real World Application Examples

Below are two real-world applications of using decorators.

Logging

Similar to the @time_it decorator you wrote in the previous lesson, there are other pieces of information that you might want to add to your functions, which can give you more insight into their behavior.

Decorators are often used to create logging features for the scope of a project. For example, additionally, to keep track of the execution time of each of your functions, you might want to write that time to a file. Additionally, you could keep track of where your code got called and from what other function, and you could use it to keep track of any errors that might come up.

Creating a @log_it decorator could combine all that functionality:

from datetime import datetime

def log_it(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        with open("activity.log", "a") as f:
            f.write(f"{func.__name__} was called at {datetime.now()}\n")
        return result
    return wrapper

Then, you could wrap any new function in your project you want to inspect more closely with @log_it without needing to change any behavior of the function itself:

@log_it
def send_email(to, subject, message):
    pass # Your code to send an email

send_email("user@example.com", "Hello", "How are you?")

Decorating send_email() with @log_it adds a log entry for every function execution to your activity.log file:

send_email was called at 2025-02-05 10:27:05.797678

Of course, the reusability aspect of decorators is the most useful part here. You can use @log_it on any other function in your program that you want to log when the function is called. Each execution will write a new line into your activity.log, which gives you an opportunity to debug your program.

If you're interested in exploring logging in more detail, then check out Python's logging module and do a web search for more detailed tutorials on how to implement a logging decorator in Python.

Web Frameworks

Another common use of decorators happens within Python web frameworks. For example, both Django and Flask use decorators as an integral part of how they operate.

For example:

  • @route() in Flask allows you to specify the URL mapping.
  • @login_required on a Django view function prevents unauthorized users from accessing that page.

Using these decorators abstracts away some common functionality that needs to be set up for many functions in a web application and, therefore, allows you to write more concise code.

Here's an abstract example of how you could implement authentication functionality as a decorator:

def authenticate(func):
    def wrapper(*args, **kwargs):
        username = input("Enter your username: ")
        password = input("Enter your password: ")
        if username == "user" and password == "pass":
            return func(*args, **kwargs)
        else:
            raise Exception("Authentication failed")
    return wrapper

@authenticate
def update_profile(user_id, new_username, new_password):
    # Your code to update the user profile
    print(f"Updating profile for user with id {user_id}")

update_profile(1, "new_user", "new_pass")

The @authenticate decorator will ask the user to input their username and password and only allow the decorated function to proceed with execution if the credentials match.

In this naive example, the username and password are hard-coded in the decorator, which, of course, isn't a good idea! However, the snippet serves as an example of how you can change the control flow by raising an exception if certain expected conditions aren't met.

After defining @authenticate, you could again use it for multiple functions that handle different parts of your web application. You could decorate any page that you require your users to log in with @authenticate and prevent unauthenticated access. Yay for tasteful decoration!

Colorful bands - Photo by https://unsplash.com/@20164rhodi Rhodi Lopez on Unsplash

Photo by Rhodi Lopez https://unsplash.com/@20164rhodi

Of course, any mature Python web framework you'd use implements decorator functionality much better than shown in this example. So make sure to use their provided decorators whenever you can instead of inventing your own!

It's not even necessary to understand in-depth how these provided decorators accomplish what they do. You can (and many programmers do) use them without the deeper insight that you gained in these lessons.

Summary: Python Decorators Real Applications

  • Decorators are often used to create logging features for the scope of a project
  • Login decorators can write errors to a file for debugging
  • Web frameworks are another common example of decorators
  • Flask uses @route to log new URL routes of your application