sureshdsk.dev

sureshdsk.dev

Python Decorators 201

Python Decorators 201

Subscribe to my newsletter and never miss my upcoming articles

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__)

Output

Help on function wrapper in module __main__:

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

wrapper
Simple decorator wrapper function

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)

@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.

Interested in reading more such articles from Suresh Kumar?

Support the author by donating an amount of your choice.

 
Share this