Decorators in Python Explained [+Examples]

Download Now: Free Introduction to Python
Danielle Richardson Ellis
Danielle Richardson Ellis

Updated:

Published:

Decorators are a powerful and elegant feature in Python that allows you to modify or extend the behavior of functions or methods without changing their actual code. They are an excellent way to apply reusable functionality across multiple functions, such as timing, caching, logging, or authentication.

decorators in python: woman next to the word decorators and python logo

Download Now: An Introduction to Python [Free Guide]

In this blog post, we will explore the concept of decorators in detail, understand how they work, and see practical examples to help you implement them in your own projects. Let's get started and unravel the magic behind decorators in Python.

What are decorators in Python?

Decorators are Python functions that allow you to wrap another function as an input and modify its behavior without altering the wrapped function’s code. They are used to extend the behavior of a particular object, such as a class, method, or function. This approach promotes reusability, modularity, and separation of concerns in your Python programs.

An Introduction to Python

A guide for marketers, developers, and data analysts. You'll learn about...

  • What Python is.
  • Programming Best Practices.
  • Coding Standards.
  • And More!

    Download Free

    All fields are required.

    You're all set!

    Click this link to access this resource at any time.

    Decorators in Python Syntax

    The syntax for a decorator in Python is quite simple. It starts with the keyword 'def' to define a function, followed by an (@) and the name of the decorator. After that, you can add any arguments needed and then pass your target function as an argument.

    This setup looks something like this:

    #Step 1: Define the decorator function def decorator_name(target_function): #Step 2: Define the wrapper function def wrapper( * args, ** kwargs): #Step 3: Do something before target_function is called results = target_function( * args, ** kwargs) # Step 4: Do something after the call to target_function return results return wrapper

    Use cases for Decorators

    Decorators are widely used for a variety of purposes, such as:

    • Timing function execution
    • Caching results (memoization)
    • Authorization and authentication
    • Logging and error handling
    • Input validation

    Next, we will look at the types of decorators in Python and see an example to show how they can be applied in practice.

    Types of Decorators in Python

    Decorators come in many forms and shapes, from built-in functions to custom user-defined functions. Here are some of the most common types:

    Function Decorator

    Function decorators allow you to extend the functionality of a single function without changing its code. They are higher-order functions that take a function as input and return a new function with the updated behavior.

    Here's an example:

    def simple_decorator(func): def wrapper(): print("Before function execution") func() print("After function execution") return wrapper @simple_decorator def greet(): print("Hello, world!") greet()

    Class Decorator

    Class decorators allow you to extend a class's behavior without changing the original source code. They are similar to function decorators but work on classes instead of functions. They take a class as input and return a new class with modified or extended behavior. Class decorators can be used for various purposes, such as adding or modifying class attributes, methods, or properties.

    def class_decorator(cls): class NewClass(cls): def new_method(self): print("This is a new method added by the decorator") return NewClass @class_decorator class MyClass: def original_method(self): print("This is the original method") obj = MyClass() obj.original_method() obj.new_method()

    Decorators with Arguments

    Decorators with arguments provide additional customization and flexibility when modifying or extending the behavior of functions or classes. These decorators accept arguments and return another decorator function, which then takes the function or class as input and returns the modified function or class.

    def decorator_with_args(arg1, arg2): def actual_decorator(func): def wrapper( * args, ** kwargs): print(f "Decorator argument 1: {arg1}") print(f "Decorator argument 2: {arg2}") func( * args, ** kwargs) return wrapper return actual_decorator @decorator_with_args("Hello", "World") def greet(name): print(f "Hi, {name}!") greet("John")

    Now that we have explored the different types of decorators in Python, you can choose the appropriate decorator type based on your use case and apply them to your projects.

    How to write a decorator in Python?

    Now that you know the basics of decorators, let's look at how to write a simple decorator in Python.

    Step-by-step explanation

    1. Define a higher-order function that takes a function as input.
    2. Inside this higher-order function, define a nested function (a wrapper) that will modify or extend the input function's behavior.
    3. Call the input function within the wrapper function and add any additional functionality you desire.
    4. Return the wrapper function from the higher-order function

    In this example, we will create a simple decorator that measures the execution time of a function.

    import time def timer_decorator(func): def wrapper( * args, ** kwargs): start_time = time.time() result = func( * args, ** kwargs) end_time = time.time() print(f "{func.__name__} executed in {end_time - start_time:.5f} seconds") return result return wrapper @timer_decorator def slow_function(): time.sleep(2) print("Slow function executed") slow_function()

    In the example, the '@' symbol is syntactic sugar that simplifies the process of applying a decorator to a function. When placed above a function definition, it indicates that the function should be passed as an argument to the decorator.

    Here's a comparison of applying the timer_decorator with and without the '@' syntax:decorators in python: example of writing decorators in python

    Decorating Functions With Parameters

    When decorating functions that accept parameters, you should use the *args and **kwargs syntax to ensure that your decorator can handle any number of positional and keyword arguments.

    The *args syntax allows your wrapper function to accept any number of positional arguments, while **kwargs enables it to accept any number of keyword arguments.

    Here is an example:

    def print_arguments_decorator(func): def wrapper( * args, ** kwargs): print(f "Positional arguments: {args}") print(f "Keyword arguments: {kwargs}") return func( * args, ** kwargs) return wrapper @print_arguments_decorator def example_function(a, b, c, x = 1, y = 2, z = 3): return a + b + c + x + y + z example_function(10, 20, 30, x = 5, y = 10, z = 15)

    Now that you know how to write simple decorators, you can start experimenting with different use cases and apply them to your Python projects.

    Decorator in Python Example

    Now, let's look at an example of how to use decorators in Python.

    Timing Function Execution

    Measuring the execution time of a function is useful for optimizing code and identifying performance bottlenecks. A timing decorator can help you achieve this without modifying the original function's code.

    import time def timer_decorator(func): def wrapper( * args, ** kwargs): start_time = time.time() result = func( * args, ** kwargs) end_time = time.time() print(f "{func.__name__} executed in {end_time - start_time:.5f} seconds") return result return wrapper @timer_decorator def slow_function(): time.sleep(2) print("Slow function executed") slow_function()

    Authorization and Authentication

    Decorators can be used to implement access control for functions or methods by checking if a user is authenticated or authorized to perform an action. This approach helps maintain a separation of concerns between authentication/authorization and the actual functionality of the function or method.

    def is_authenticated(user): return user == "authenticated_user" def authentication_decorator(func): def wrapper( * args, ** kwargs): user = kwargs.get("user") if is_authenticated(user): return func( * args, ** kwargs) else : raise PermissionError("User is not authenticated") return wrapper @authentication_decorator def restricted_function(user = None): print("Access granted to the restricted function") restricted_function(user = "authenticated_user")

    Logging and Error Handling

    Decorators can be employed to log information about function calls or handle errors and exceptions in a consistent manner across multiple functions without modifying their code.

    import logging def logging_decorator(func): def wrapper( * args, ** kwargs): try: logging.info(f "Calling {func.__name__} with arguments {args} and keyword arguments {kwargs}") result = func( * args, ** kwargs) logging.info(f "Function {func.__name__} executed successfully") return result except Exception as e: logging.error(f "An error occurred while executing {func.__name__}: {e}") raise return wrapper @logging_decorator def example_function(a, b): return a / b example_function(10, 5) example_function(10, 0)

    Explore the Power of Decorators in Python

    It's amazing how powerful decorators in Python can be. They are like superheroes with different superpowers. Each type of decorator allows us to use a superpower that can help make our code better, easier to read, and more maintainable.

    Decorators may take some time to get used to but once you understand their power and capabilities, there's no limit on what these heroes can do for your code.

    An Introduction to Python

    A guide for marketers, developers, and data analysts. You'll learn about...

    • What Python is.
    • Programming Best Practices.
    • Coding Standards.
    • And More!

      Download Free

      All fields are required.

      You're all set!

      Click this link to access this resource at any time.

       

      Topics: What Is Python?

      Related Articles

      A guide for marketers, developers, and data analysts.

        CMS Hub is flexible for marketers, powerful for developers, and gives customers a personalized, secure experience

        START FREE OR GET A DEMO