📜  Python| functools.wraps()函数

📅  最后修改于: 2022-05-13 01:54:32.994000             🧑  作者: Mango

Python| functools.wraps()函数

functools是用于高阶函数(作用于或返回其他函数的函数)的标准Python模块。 wraps() 是一个装饰器,应用于装饰器的包装函数。它通过复制 __name__、__doc__(文档字符串)等属性来更新包装函数,使其看起来像被包装的函数。

示例 1:没有 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__)


Python3
print("First Function")
help(first_function)
 
print("\nSecond Function")
help(second_function)


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


Python3
print("First Function")
help(first_function)
 
print("\nSecond Function")
help(second_function)


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


Python3
print("First Function")
help(first_function)
 
print("\nSecond Function")
help(second_function)


输出:
wrapper
A wrapper function
wrapper
A wrapper function

现在如果我们写 help(first_function) 和 help(second_function) 会发生什么

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

虽然上面的代码在逻辑上可以正常工作,但是如果您正在编写 API 或库并且有人想知道您的函数的功能及其名称或只是输入 help(yourFunction),请考虑这一点,它将始终显示包装函数的名称和文档字符串.如果您对不同的函数使用相同的包装函数,这会变得更加混乱,因为它将为每个函数显示相同的细节。
理想情况下,它应该显示包装函数。手动解决方案是在返回之前在包装函数中分配 __name__、__doc__ 属性。

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

这样就解决了问题,但是如果我们再次输入 help(yourFunction),

Python3

print("First Function")
help(first_function)
 
print("\nSecond Function")
help(second_function)

对于 first_function:帮助(first_function)

输出:
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

正如您所看到的,它仍然有一个问题,即函数的签名,它显示了包装函数使用的签名(这里是通用签名)。此外,如果您要实现许多装饰器,那么您必须为每个装饰器编写这些行。
所以为了节省时间和增加可读性,我们可以使用functools.wraps() 作为装饰器来包装函数
示例(使用 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

现在,如果我们输入 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