关于python:装饰是如何工作的?

How decorator works?

本问题已经有最佳答案,请猛点这里访问。

我正在试图弄清楚修饰符在Python中是如何工作的。但是,有两件事我说不清楚,所以如果有人能帮助我理解修饰符在Python中的工作原理,我将不胜感激!

这是我刚刚编写的示例代码,以查看它是如何工作的。

1
2
3
4
5
6
7
8
9
10
11
In [22]: def deco(f):
   ....:     def wrapper():
   ....:         print("start")
   ....:         f()
   ....:         print("end")
   ....:     return wrapper

In [23]: @deco
   ....: def test():
   ....:     print("hello world")
   ....:

输出1

1
2
3
4
In [24]: test()
start
hello world
end

我不明白的第一件事是,当我调用test()时,它为什么输出"start"、"hello world"、"end"。我了解到,当我调用test()时,它在内部调用"deco(test)"。如果是这样,它应该返回"wrapper"函数对象,而不是输出字符串。但是,它输出字符串作为结果。我想知道它是如何在内部完成这项工作的。

输出2

1
2
3
4
5
6
7
8
9
10
11
In [28]: i = deco(test)

In [29]: i
Out[29]: <function __main__.wrapper>

In [30]: i()
start
start
hello world
end
end

我称之为"deco(测试)"只是为了看看它输出的结果。如上图所示,它返回"wrapper"函数对象,在我将它赋给一个变量并调用"wrapper"函数后,它输出两个"start"和一个"hello world"以及两个"end"函数。内部情况如何?为什么"开始"和"结束"分别输出两次?

有人能帮我了解一下这是怎么回事吗?


I learned that when I call test(), it calls"deco(test)" internally. If so, it should return a"wrapper" function object instead of outputting strings. But, it outputs strings as the result. I'm wondering how it's doing the job internally.

不完全是这样,应用一个装饰器就是语法上的糖分(这意味着用一种很好的方式来做其他可能的事情)。等效操作是

1
2
3
def test():
    print("Hello, world!")
test = deco(test) # note that test is overwritten by the wrapper that deco returns

为了说明这一点,请考虑以下示例

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> def deco(f):
...     print 'applying deco' # this will print when deco is applied to test
...     def wrapper():
...             print("start")
...             f()
...             print("end")
...     return wrapper
...
>>> @deco
... def test():
...     print("Hello world!")
...
applying deco

请注意,只要定义了函数,就会应用decorator。这与上述"等效操作"相匹配。

在第二种情况下,您将看到双打印语句,因为您正在手动将deco应用于已修饰的测试函数。