geekdoc-python-zh/docs/pythonlibrary/python-functools-wraps.md

4.1 KiB
Raw Blame History

Python -如何使用 functools.wraps

原文:https://www.blog.pythonlibrary.org/2016/02/17/python-functools-wraps/

今天我想谈谈一个鲜为人知的工具。它叫做 包裹 ,是 functools 模块的一部分。您可以使用包装作为修饰器来修复文档字符串和被修饰函数的名称。为什么这很重要?起初,这听起来像是一个奇怪的边缘案例,但是如果你正在编写一个 API 或者其他人会使用的任何代码,那么这可能是很重要的。原因是当你使用 Python 的内省来理解别人的代码时,修饰过的函数会返回错误的信息。让我们来看一个简单的例子,我称之为decrument . py:


# decorum.py

#----------------------------------------------------------------------
def another_function(func):
    """
    A function that accepts another function
    """

    def wrapper():
        """
        A wrapping function
        """
        val = "The result of %s is %s" % (func(),
                                          eval(func())
                                          )
        return val
    return wrapper

#----------------------------------------------------------------------
@another_function
def a_function():
    """A pretty useless function"""
    return "1+1"

#----------------------------------------------------------------------
if __name__ == "__main__":
    print(a_function.__name__)
    print(a_function.__doc__)

在这段代码中,我们用的另一个 _ 函数来修饰名为 a_function 的函数。您可以使用函数的 namedoc 属性打印出 a_function 的名称和 docstring。如果您运行这个示例您将得到以下输出:


wrapper

        A wrapping function

这是不对的!如果你在 IDLE 或者解释器中运行这个程序,它会变得更加明显,变得非常混乱,非常快。


>>> import decorum
>>> help(decorum)
Help on module decorum:

NAME
    decorum - #----------------------------------------------------------------------

FILE
    /home/mike/decorum.py

FUNCTIONS
    a_function = wrapper()
        A wrapping function

    another_function(func)
        A function that accepts another function

>>> help(decorum.a_function)
Help on function other_func in module decorum:

wrapper()
    A wrapping function

基本上,这里发生的是装饰器将被装饰的函数的名称和 docstring 改为它自己的。


快来救援!

我们如何解决这个小问题Python 开发者在 functools.wraps 中给了我们解决方案!让我们来看看:


from functools import wraps

#----------------------------------------------------------------------
def another_function(func):
    """
    A function that accepts another function
    """

    @wraps(func)
    def wrapper():
        """
        A wrapping function
        """
        val = "The result of %s is %s" % (func(),
                                          eval(func())
                                          )
        return val
    return wrapper

#----------------------------------------------------------------------
@another_function
def a_function():
    """A pretty useless function"""
    return "1+1"

#----------------------------------------------------------------------
if __name__ == "__main__":
    #a_function()
    print(a_function.__name__)
    print(a_function.__doc__)

这里我们从 functools 模块导入包装器,并将其用作 another_function 内部嵌套包装器函数的装饰器。如果这次运行它,输出将会发生变化:


a_function
A pretty useless function

现在我们又有了正确的名称和 docstring。如果你进入你的 Python 解释器,帮助功能现在也可以正常工作了。我将跳过把它的输出放在这里,留给你去尝试。


包扎

wraps decorator 很像一匹只会一招的小马,但是当你需要它的时候,它非常方便。如果您碰巧注意到您的函数没有给您正确的名称或 docstring那么您现在知道如何非常容易地修复它了。祝您编码愉快