DEV Community

Cover image for Python Decorators 201
Suresh Kumar for Kubernetes Community Days Chennai

Posted on • Originally published at sureshdsk.dev

Python Decorators 201

In the previous article Python decorators 101 we learnt, how to create a simple function based decorator and how it works under the hood. In this article, we will improve the traceability and the readability of the decorator function.

Let's add some docstrings to our code. A docstring is a string literal that is written as the first statement in a module, function, class, or method definition. It becomes the doc special attribute of that object. docstring acts a a built-in documentation.


def hello_decorator(func):
    """Simple decorator function"""

    def wrapper(*args, **kwargs):
        """Simple decorator wrapper function"""
        result = func(*args, **kwargs)
        return result

    return wrapper


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


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


if __name__ == '__main__':

    help(add)

    print(add.__name__)
    print(add.__doc__)
Enter fullscreen mode Exit fullscreen mode

Output

Help on function wrapper in module __main__:

wrapper(*args, **kwargs)
    Simple decorator wrapper function

wrapper
Simple decorator wrapper function

Enter fullscreen mode Exit fullscreen mode

As you notice that, help and doc string of add function returns the doc string from the decorator wrapper function. This is not good for readability and IDEs will show wrong definition and signature of the decorated function. we don't want this to happen. Lets see how we can fix this,

Fix decorated function docs using functools

from functools import wraps


def hello_decorator(func):
    """Simple decorator function"""

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

    return wrapper


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


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


if __name__ == '__main__':

    help(add)

    print(add.__name__)
    print(add.__doc__)

    output1 = add(2, 2)
    print('Result:: ', output1)

    print("=" * 25)
    help(multiply)
    print(multiply.__name__)
    print(multiply.__doc__)
    output2 = multiply(4, 2)
    print('Result:: ', output2)

Enter fullscreen mode Exit fullscreen mode

@wraps function tracks both original function and decorator function and fixes the doc string properly.

In the next article, we will implement various kinds decorator recipes. Stay tuned for upcoming articles. Connect with me on twitter to get my future articles.

Top comments (0)