I came across the following code snippet in Python:
def log_function(argument):
def decorator_factory(func):
@functools.wraps(func)
def handler_decorator(*args, **kwargs):
time_start = time()
print(f"Foi iniciada a execução: {argument}")
result = func(*args, **kwargs)
time_end = time()
print(
f"Foi finalizada a execução: {argument}"
f" demorou {(time_end - time_start):.4f} segundos"
)
return result
return handler_decorator
return decorator_factory
Basically, this is a decorator used to provide log for calling some function, ok?!
Example:
But these wraps there? @functools.wraps(func)
The @functools
module, provides tools for working with functions and object calls, the wraps()
this takes a function used in a decorator and adds the functionality of copying over the function name, docstring, arguments list, etc.
Example:
Let's comment the excerpt @functools.wraps(func)
def log_function(argument):
def decorator_factory(func):
# @functools.wraps(func)
def handler_decorator(*args, **kwargs):
time_start = time()
print(f"Foi iniciada a execução: {argument}")
result = func(*args, **kwargs)
time_end = time()
print(
f"Foi finalizada a execução: {argument}"
f" demorou {(time_end - time_start):.4f} segundos"
)
return result
return handler_decorator
return decorator_factory
When we run the test function we get the same operation, however, notice that there was a switch and the f()
function is now the handler_decorator
function:
As we replace the @functools.wraps(func)
snippet, notice that we continue with the same f()
function without switching to the handler_decorator
function.
Conclusion:
To avoid problems when creating our decorators, such as losing information from the calling function, we use this wraps()
function. ;)