1 装饰器
装饰器的基础是闭包,同时装饰器是闭包的一种应用,总的来说,装饰器就是对原函数的一种功能扩展
1.1单个装饰器
我们先来认识下装饰器的语法
def decorator(func):
def funcdeco():
print(f"{func.__name__} is running")#修饰部分
func()#原有函数功能实现
return funcdeco
@decorator
def fun():
pass
fun1=fun#这里得到的是funcdeco函数
fun1()#开始装饰fun并执行fun函数
执行结果:
fun is running
1.2 传参的装饰器
1.2.1 函数带参数
在上面的例子中,我们发现所执行的函数是不带任何参数的,也就是无参无返,若我们要执行一个有参有返的函数的话,我们只需要在fundeco()中接受参数
def funcdeco(*args,**kawrgs):#接受参数
print(f"{func.__name__} is running")
func(*args,**kawrgs)#原有函数传入参数
return funcdeco
1.2.2 修饰带参数
现在我们要给装饰函数加入一些装饰信息,比如说进程ID,来修饰这个函数的进程执行中的ID
@decorator("652156")#进程id为652156
def fun():
pass
这个时候我们就有必要对decorator函数进行相应的修改,那就是再增加一层闭包
def decorator(pid):
def decoratorSub(func):
def funcdeco(*args):
print("pid: %s function name:%s"%(pid,func.__name__))
return func(*args)
return funcdeco
return decoratorSub
@decorator("652156")#进程id为652156
def fun(*args):
pass
fun()
执行结果:
pid: 652156 function name:fun
1.3 多个装饰器
如果有多个装饰修饰器的话,那么被装饰的顺序是怎样的,下面给出一个例子
def log3(func):
print("log3")
def wrapper3(*args, **kw):
print('log3 call %s():' % func.__name__)
func(*args, **kw)
return wrapper3
def log2(func):
print("log2")
def wrapper2(*args, **kw):
print('log2 call %s():' % func.__name__)
func(*args, **kw)
return wrapper2
def log1(func):
print("log1")
def wrapper1(*args, **kw):
print('log1 call %s():' % func.__name__)
func(*args, **kw)
return wrapper1
@log1
@log2
@log3
def now():
print('2015-3-25')
now()
执行结果:
log3
log2
log1
log1 call wrapper2():
log2 call wrapper3():
log3 call now():
2015-3-25
如果你对这样的结果感到不解的话,让我们猜想一下多种装饰器的函数究竟是怎样工作的,下面给出一个函数now2(为了区分now),并且给出一段代码执行来猜测多个装饰器是如何工作的
def now2():
print("2015-3-25")
f1=log3(now2)
f2=log2(f1)
f3=log1(f2)
f3()
结果打印:
log3
log2
log1
log1 call wrapper2():
log2 call wrapper3():
log3 call now2():
2015-3-25
很明显这里的结果和now的结果是一样的,也就是说我们的猜想得到了证实,将f3展开
f
3
=
l
o
g
1
(
l
o
g
2
(
l
o
g
3
(
n
o
w
2
)
)
)
f_3=log_1(log_2(log_3(now_2)))
f3=log1(log2(log3(now2)))
如果我们不执行f3而是将f3打印出来
<function __main__.log1.<locals>.wrapper1(*args, **kw)>
也就是说
l
o
g
1
(
l
o
g
2
(
l
o
g
3
(
n
o
w
2
)
)
)
−
>
w
r
a
p
p
e
r
1
−
>
l
o
g
1
l
o
g
2
(
l
o
g
3
(
n
o
w
2
)
)
−
>
w
r
a
p
p
e
r
2
−
>
l
o
g
2
l
o
g
3
(
n
o
w
2
)
−
>
w
r
a
p
p
e
r
3
−
>
l
o
g
3
log_1(log_2(log_3(now_2)))->wrapper1->log_1\\ log_2(log_3(now_2))->wrapper2->log_2\\ log_3(now_2)->wrapper3->log_3\\
log1(log2(log3(now2)))−>wrapper1−>log1log2(log3(now2))−>wrapper2−>log2log3(now2)−>wrapper3−>log3
在下面几行中我们发现log1,log2,log3是按照顺序出现的,但是后面的信息好像不是很规则
log1 call wrapper2():
log2 call wrapper3():
log3 call now2():
这其实不难理解,刚才我们是像洋葱一样一层一层往外拨开,现在我们从洋葱内部一步一步扩展
log_3(now_2)#表示log_3修饰的now_2函数
所以会打印log3 call now2():
并且会执行now2()函数
这一步执行完后就会返回一个wrapper3给log_2(log_3(now_2))也就是
log_2(wrapper3)#表示log_2修饰wrapper3
所以会打印log2 call wrapper3()
并且会执行wrapper3()函数
并且返回一个wrapper2给log_1(log_2(log_3(now_2)))也就是
log1(wrapper2)#表示log_2修饰wrapper3
所以会打印log1 call wrapper2():
并且会执行wrapper2()函数
别忘了当我们使用f3()的时候已经调用了wrapper1()函数
现在让我们回到洋葱的外面
因此多个装饰器的运行过程如下
wrapper1(wrapper2)->wrapper2(wrapper3)->wrapper3(now2)->now2()
到了这里,我想你对装饰器有了一定的了解