装饰者如何运作?

时间:2014-03-11 05:23:22

标签: python python-decorators

我正在试图弄清楚装饰器在python中是如何工作的。 但是,有两件事我无法说清楚,所以如果有人帮助我理解装饰器在python中是如何工作的,我感激不尽!

这是我刚刚编写的示例代码,用于查看其工作原理。

In [22]: def deco(f):
   ....:     def wrapper():
   ....:         print("start")
   ....:         f()
   ....:         print("end")
   ....:     return wrapper

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

输出1

In [24]: test()
start
hello world
end

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

输出2

In [28]: i = deco(test)

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

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

我打电话给“deco(测试)”只是为了看看它输出的结果。 如上所示,它返回“包装器”函数对象,在将其分配给变量并调用“包装器”函数后,它输出两个“开始”和一个“hello world”和两个“end”。 内部发生了什么?为什么“开始”和“结束”分别输出两次?

有人可以帮我理解这是如何运作的吗?

1 个答案:

答案 0 :(得分:5)

  

我了解到当我调用test()时,它会在内部调用“deco(test)”。如果是这样,它应该返回一个“包装器”函数对象而不是输出字符串。但是,它会输出字符串作为结果。我想知道它是如何在内部完成工作的。

不完全,应用装饰器是 syntatic sugar (意味着做一些其他可能的好方法)。等效操作是

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

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

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

请注意,只要定义了函数,装饰器就会应用。这符合上述“等效操作”。

在第二种情况下,当您手动将deco应用于已装饰的测试函数时,您将看到双重打印语句。