functools es un módulo estándar de Python para funciones de orden superior (funciones que actúan sobre otras funciones o las devuelven). wraps() es un decorador que se aplica a la función de envoltura de un decorador. Actualiza la función contenedora para que parezca una función envuelta copiando atributos como __name__, __doc__ (la string de documentación), etc.
Sintaxis: @functools.wraps(envuelto, asignado = WRAPPER_ASSIGNMENTS, actualizado = WRAPPER_UPDATES)
Parámetros:
envuelto : El nombre de la función que será decorado por la función contenedora.
asignado : tupla para especificar qué atributos de la función original se asignan directamente a los atributos coincidentes en la función contenedora. De forma predeterminada, se establece en WRAPPER_ASSIGNMENTS (que asigna a la función contenedora __module__, __name__, __qualname__, __annotations__ y __doc__, la string de documentación)
actualizado: Tupla para especificar qué atributos de la función contenedora se actualizan con los atributos correspondientes de la función original. De forma predeterminada, se establece en WRAPPER_UPDATES (que actualiza el __dict__ de la función contenedora, es decir, el diccionario de instancias).
Ejemplo 1: Sin functools.wraps()
Python3
def a_decorator(func): def wrapper(*args, **kwargs): """A wrapper function""" # Extend some capabilities of func func() return wrapper @a_decorator def first_function(): """This is docstring for first function""" print("first function") @a_decorator def second_function(a): """This is docstring for second function""" print("second function") print(first_function.__name__) print(first_function.__doc__) print(second_function.__name__) print(second_function.__doc__)
wrapper A wrapper function wrapper A wrapper function
Ahora, ¿qué sucederá si escribimos ayuda (primera_función) y ayuda (segunda_función)?
Python3
print("First Function") help(first_function) print("\nSecond Function") help(second_function)
First Function Help on function wrapper in module __main__: wrapper(*args, **kwargs) A wrapper function Second Function Help on function wrapper in module __main__: wrapper(*args, **kwargs) A wrapper function
Si bien el código anterior funcionará lógicamente bien, considere esto si está escribiendo una API o una biblioteca y alguien quiere saber qué hace su función y su nombre o simplemente escriba ayuda (su función), siempre mostrará el nombre de la función contenedora y la string de documentación . Esto se vuelve más confuso si ha utilizado la misma función contenedora para diferentes funciones, ya que mostrará los mismos detalles para cada una de ellas.
Idealmente, debería mostrar el nombre y la string de documentación de la función envuelta en lugar de la función de envoltura. La solución manual sería asignar los atributos __name__, __doc__ en la función de ajuste antes de devolverlo.
Python3
def a_decorator(func): def wrapper(*args, **kwargs): """A wrapper function""" # Extend some capabilities of func func() wrapper.__name__ = func.__name__ wrapper.__doc__ = func.__doc__ return wrapper @a_decorator def first_function(): """This is docstring for first function""" print("first function") @a_decorator def second_function(a): """This is docstring for second function""" print("second function") print(first_function.__name__) print(first_function.__doc__) print(second_function.__name__) print(second_function.__doc__)
first_function This is docstring for first function second_function This is docstring for second function
Esto resuelve el problema, pero ¿y si volvemos a escribir help(yourFunction),
Python3
print("First Function") help(first_function) print("\nSecond Function") help(second_function)
Para primera_función: ayuda(primera_función)
First Function Help on function first_function in module __main__: first_function(*args, **kwargs) This is docstring for first function Second Function Help on function second_function in module __main__: second_function(*args, **kwargs) This is docstring for second function
Como puede ver, todavía tiene un problema, es decir, la firma de la función, muestra la firma utilizada por la función contenedora (aquí, firma genérica) para cada una de ellas. Además, si está implementando muchos decoradores, debe escribir estas líneas para cada uno de ellos.
Entonces, para ahorrar tiempo y aumentar la legibilidad, podríamos usar functools.wraps() como decorador para la función contenedora .
Ejemplo (con functools.wraps())
Python3
from functools import wraps def a_decorator(func): @wraps(func) def wrapper(*args, **kwargs): """A wrapper function""" # Extend some capabilities of func func() return wrapper @a_decorator def first_function(): """This is docstring for first function""" print("first function") @a_decorator def second_function(a): """This is docstring for second function""" print("second function") print(first_function.__name__) print(first_function.__doc__) print(second_function.__name__) print(second_function.__doc__)
first_function This is docstring for first function second_function This is docstring for second function
Ahora, si escribimos help(first_function) –
Python3
print("First Function") help(first_function) print("\nSecond Function") help(second_function)
First Function Help on function first_function in module __main__: first_function() This is docstring for first function Second Function Help on function second_function in module __main__: second_function(a) This is docstring for second function
Publicación traducida automáticamente
Artículo escrito por manishkhurana y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA