DEV Community ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป

Cover image for Python decorators with parameters

Python decorators with parameters

In the previous articles on the Python decorator series, we have learnt decorators, how they work and to implement a simple function based decorator and a class based decorator. In this article we will learn to create decorators that supports parameters.

Function based decorator with parameters

from functools import wraps


def hello_decorator(num):
    """Simple decorator function that supports parameters"""

    def inner_func(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            """Simple decorator wrapper function"""
            result = func(*args, **kwargs)
            result = result + num
            return result
        return wrapper
    return inner_func


@hello_decorator(100)
def add(a, b):
    """Simple function that returns sum of two numbers"""
    return a + b


@hello_decorator(200)
def multiply(a, b):
    """Simple function that returns multiplication of two numbers"""
    return a * b


if __name__ == '__main__':
    output1 = add(2, 2)
    print('Result:: ', output1)
    print("=" * 25)

    output2 = multiply(4, 2)
    print('Result:: ', output2)


Enter fullscreen mode Exit fullscreen mode

As you notice, the structure is little different from our previous examples,

  • decorator takes a parameter @hello_decorator(100) - this is how we can pass arguments to our decorator
  • hello_decorator function returns an inner function.
  • inner_func takes the function to be decorated as an argument and returns the wrapper function.
  • wrapper function executes the add function and manipulates the output based on argument result = result + num and returns the final result

Class based decorator with parameters

from functools import wraps


class HelloDecorator:
    """Simple class decorator"""

    def __init__(self, num):
        self.num = num

    def __call__(self, func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            """Simple class call method"""
            result = func(*args, **kwargs)
            result = result + self.num
            return result
        return wrapper


@HelloDecorator(100)
def add(a, b):
    """Simple function that returns sum of two numbers"""
    return a + b


@HelloDecorator(200)
def multiply(a, b):
    """Simple function that returns multiplication of two numbers"""
    return a * b


if __name__ == '__main__':
    output1 = add(2, 2)
    print('Result:: ', output1)

    output2 = multiply(4, 2)
    print('Result:: ', output2)
Enter fullscreen mode Exit fullscreen mode

This class based decorator with parameters is pretty much similar to our simple function based decorator. The best thing with this method is, we do not need the extra boilerplate code to fix the doc strings.

So now to implement decorator with arguments, I would prefer class based approach. since it is very intuitive and doesn't requires an additional inner function and additional boilerplate code fixes for docs.

So far, we've covered the basic decorator implementation with examples. In the next article, we will implement various kinds decorator recipes. Stay tuned for upcoming articles. Subscribe to the newsletter and Connect with me on twitter to get my future articles.

Top comments (0)

An Animated Guide to Node.js Event Lop

Node.js doesnโ€™t stop from running other operations because of Libuv, a C++ library responsible for the event loop and asynchronously handling tasks such as network requests, DNS resolution, file system operations, data encryption, etc.

What happens under the hood when Node.js works on tasks such as database queries? We will explore it by following this piece of code step by step.