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.