1. 简介
装饰器本质上是一个函数,该函数的返回值也是一个函数对象。装饰器能够在其他函数不改变其代码和执行方式的前提下增加其功能,这样我们可以抽离出大量的与特定函数无关的代码放到装饰器中以重用。
2. 无参装饰器
首先要说的是这里的无参指的是修饰器本身没有参数,要修饰的函数有没有参数都可以,先看下面这个例子。
def a():
print "do something here"
a()
如果我们想增强函数a的功能而不修改其代码,我们可以写另外一个函数,这个函数会调用a(),并且可以在其调用前后加上我们需要的额外操作。
def a():
print "do something here"
def b():
print "do something before call a()"
temp = a()
print "do something after call a()"
return temp
b()
如果想让b这个函数不仅仅服务于a这个函数,我们只要把要加强的函数传入到b的参数中即可。
def a():
print "do something here"
def b(fun):
print "do something before call fun()"
temp = fun()
print "do something after call fun()"
return temp
b(a)
现在执行的是b函数,如果我就是想通过a()来运行怎么办呢。那就得为变量a赋值一个新的函数对象。
我们创建一个函数(这里是b函数),它的参数接收其他函数(这里是a函数),返回一个函数对象(这里是c函数),我们将返回的函数对象c赋值给传入的函数变量名a,即a = b(a),这样再次执行a()就能得到增强的版本。
def a():
print "do something here"
def b(fun):
def c():
print "do something before call fun()"
fun()
print "do something after call fun()"
return c
a = b(a)
a()
如果要修饰的函数有参,那也很简单,只需要在返回的函数对象c添加收集参数,调用传入的函数fun时加上即可。
def a(p1,p2):
print (p1,p2)
def b(fun):
def c(*args,**kwargs):
print "do something before call fun()"
fun(*args,**kwargs)
print "do something after call fun()"
return c
a = b(a)
a('1','2')
最后Python为装饰器提供了语法糖,只要在要装饰的函数上一行添加@加上装饰器函数名就可以不用手动装饰啦,即省略了a = b(a)这一句。
def b(fun):
def c(*args,**kwargs):
print "do something before call fun()"
fun(*args,**kwargs)
print "do something after call fun()"
return c
@b
def a(p1,p2):
print (p1,p2)
a('1','2')
3.带参数的装饰器
如果装饰器本身带参数的话,那么通过调用带参的装饰器函数得到无参的装饰器函数即可啦。
def b(p1,p2,p3):
def c(fun):
def d(*args,**kwargs):
print (p1,p2,p3)
print "do something before call fun()"
fun(*args,**kwargs)
print "do something after call fun()"
return d
return c
def a(p1,p2):
print (p1,p2)
b = b('3','4','5')
a = b(a)
a('1','2')
同样可以用@的语法糖写出下面的优雅版本。
def b(p1,p2,p3):
def c(fun):
def d(*args,**kwargs):
print (p1,p2,p3)
print "do something before call fun()"
fun(*args,**kwargs)
print "do something after call fun()"
return d
return c
@b('3','4','5')
def a(p1,p2):
print (p1,p2)
a('1','2')