装饰器允许在函数或类中注入或修改代码。例如,假设你想在某个函数的开始和结束时执行某些操作,用装饰器就可以完成这样的任务。看一个例子你就会明白了。
In [18]: class myDecorator(object):
...:
...: def __init__(self, f):
...: print "inside myDecorator.__init__()"
...: f()
...:
...: def __call__(self):
...: print "inside myDecorator.__call__()"
...:
...: @myDecorator
...: def aFunction():
...: print "inside aFunction()"
...:
当编译器编译代码时,输出结果为,
inside myDecorator.__init__()
inside aFunction()
这说明装饰器不需要我们自己调用,编译器会自动帮我们调用。看看经过装饰器装饰以后aFunction是什么模样?
In [19]: aFunction
Out[19]: <__main__.myDecorator at 0xf16b630>
可以看出此时的aFunction变成了myDecorator类的一个实例对象了,而不再是函数对象了,上述过程其实等价于:
In [23]: class myDecorator(object):
...:
...: def __init__(self, f):
...: print "inside myDecorator.__init__()"
...: f()
...:
...: def __call__(self):
...: print "inside myDecorator.__call__()"
...:
...: def aFunction():
...: print "inside aFunction()"
...:
In [24]: aFunction=myDecorator(aFunction)
inside myDecorator.__init__()
inside aFunction()
In [25]: aFunction
Out[25]: <__main__.myDecorator at 0xf16b1d0>
装饰器返回的对象要求它可以作为一个函数使用,这意味着它必须是可调用的。
因此,我们用作装饰器的任何类都必须实现特殊方法__call__。这样我们就可以像调用函数一样调用类的实例对象。
In [26]: aFunction()
inside myDecorator.__call__()
在来看另外一个例子:
In [27]: class entryExit(object):
...:
...: def __init__(self, f):
...: self.f = f
...:
...: def __call__(self):
...: print "Entering", self.f.__name__
...: self.f()
...: print "Exited", self.f.__name__
...:
...: @entryExit
...: def func1():
...: print "inside func1()"
...:
...: @entryExit
...: def func2():
...: print "inside func2()"
...:
...: func1()
...: func2()
...:
Entering func1
inside func1()
Exited func1
Entering func2
inside func2()
Exited func2
通过输出我们可以看到整个的执行流程:
类装饰器entryExit装饰函数func1和func2,装饰器返回的结果是两个类的实例对象,分别赋给func1和func2。此时的func1和func2不在指向函数对象,而是指向类的两个实例对象。
构造函数中保存的属性是作为参数传入的func1和func2函数。
执行fun1()和fun2(),调用__call__方法,__call__方法内部调用了作为参数传入的fun1和fun2函数
参考:https://www.artima.com/weblogs/viewpost.jsp?thread=240808