在 Python 中格式化装饰器

Format a decorator in Python

咆哮 - 为什么人们说 'a decorator is a function that returns another function'?这个定义没有意义,因为如果装饰器就是这样,为什么不只使用第二个函数而不用第一个呢? - 结束咆哮

幸运的是,我在这里找到了一个更合理的定义: http://thecodeship.com/patterns/guide-to-python-function-decorators/

不幸的是,我还是不明白这些例子,比如这个:

def get_text(name):
   return "lorem ipsum, {0} dolor sit amet".format(name)

def p_decorate(func):
   def func_wrapper(name):
       return "<p>{0}</p>".format(func(name))
   return func_wrapper

my_get_text = p_decorate(get_text)

print my_get_text("John")

#Outputs "<p>lorem ipsum, John dolor sit amet</p>"

请注意,post 已有两年多了,作者尚未对任何评论做出回应。

这是我的问题:为什么不输出

"<p>John</p>"

还是错误?整个字符串如何进入 p 标签而不只是名称?

编辑:我刚刚发现您链接了一篇文章,从字面上逐步解释了装饰器是什么...但是已经输入了,所以...

Python 中有一个称为闭包/函数闭包的特性。

自从我试图解释/理解闭包/装饰器在较低级别发生的事情以来已经有一段时间了,所以这实际上可能是错误的。

函数func_wrapper每次调用p_decorate时都会被重新定义,func_wrapper会记住包含的内容 命名空间在定义时的样子。

什么意思:

例如,假设您有一些嵌套在 p_decorate 中的外部变量,您会期望这会引发错误,因为当 func_wrapper 被调用并尝试使用这个变量,但它不会,因为封闭的命名空间是 "remembered"

在 python 3 中是 __closure__,在 python 2 中是 func_closure 以下。

def get_text(name):
    return "lorem ipsum, {0} dolor sit amet".format(name)

def p_decorate(func):
    def func_wrapper(name):
        return "<p>{0}</p>".format(func(name)) #Cached result
    print(func_wrapper.func_closure)
    return func_wrapper

my_get_text1 = p_decorate(get_text)
my_get_text2 = p_decorate(get_text2)

func_closure 东西:

my_get_text1 >>> (<cell at 0x*: function object at 0x*>,)
my_get_text2 >>> (<cell at 0x(different address): function object at (diff address)>,)

我们没有将不同的函数传递给 func_wrapper 函数,而是构建 func_wrapper 函数的自定义版本,"remembers" 它应该使用 [=21] 调用什么函数=].

如果您为 my_get_text1my_get_text2 两次传入相同的函数,您将对 func_wrapper.func_closure 位、内存地址和 [=25 的所有内容拥有完全相同的东西=], 因为它是相同的功能。 (当您实际使用可能不同的参数调用它时减去。)

装饰器:

正如您所指出的,装饰器只是一个可调用函数,它接受一个函数作为参数,returns 一个替换函数。在您的代码中,这将分别是 p_decoratorfunc_wrapper

如果你想以 OOP 的方式考虑这个......你可以将 p_decorate 视为函数 func_wrapper 的构造函数,其中 func 充当私有成员变量/属性,因为你或多或少基本上构建了一个带有硬编码参数的函数 func.

为什么 returns 它的作用:

希望以上都是正确的+有意义...然后,它returns你看到的值,因为你已经通过了get_text函数"remembered"并且因为func_wrapper 被返回......你正在调用 func_wrapper(arg) 参数 John 现在在这个里面...... func_wrapper returns 以下:

"<p>{0}</p>".format(func(name))"

funcget_text。因此,get_text 被称为 returns...

"lorem ipsum, {0} dolor sit amet".format(name)

然后在开始和结束 p 标记之间进行格式化,然后返回。

您可以拥有多层嵌套函数,并且与 python 中的几乎所有内容一样,它一直是海龟。

为什么还要使用装饰器?

在这个例子中,我认为你是对的,我只使用第二个函数,因为这是一个非常无用的例子。

但是,请考虑更具体的事情。我将使用一个常见的 django 装饰器作为我头脑中的例子。即使您不熟悉 Django,这仍然有意义。

在 django 中,您有呈现网页的函数/视图,有时您可能希望要求用户登录才能查看页面。

现在,如果您必须为每个函数编写自定义逻辑怎么办

那就太糟糕了。相反,有一个名为 @login_required 的漂亮装饰器,您只需将它放在您想要此功能的函数的顶部,您就可以节省大量时间/重复代码,因为这个装饰器将这个自定义逻辑包装在您的函数周围已经应用到。

装饰器主要用于扩展/自定义功能而无需重新编码的情况。

比函数更进一步....如果您想将其应用于 class 的方法怎么办?也许他们都符合某些标准?必须为每个方法都这样做会有点乏味并且可能很烦人。您可以编写一个装饰器来包装 class 并将其自动神奇地应用到每个函数,而不是用 @decorator_name 包装每个方法。