1.装饰器的特点
装饰器是在闭包上的升级,是传参为函数的闭包
先来看下以下这段代码
def decorate(func): #装饰器接收一个函数作为入参
print('外层打印测试')
def inner(): #内部函数
func() #调用接收的函数
print('-------刷墙-------')
print('内层加载完成……')
return inner #返回内部函数名
@decorate #装饰器
def house(): #被装饰函数
print('我是毛坯房')
运行下,看下控制台输出
外层打印测试
内层加载完成……
这里奇怪的地方是,在以上代码中我们只是声明了两个函数docorate和house,并没有调用任何函数,运行后控制台竟然会打印出decorate中的信息,原因就在于我们使用了装饰器@decorate
所以装饰器的功能如下:
只要使用了装饰器,就会自动执行以下步骤
1.@decorate下的函数就是被装饰函数
2.被装饰器作为参数传给装饰器decorate
3.底层自动执行decorate函数
4.然后把返回值传给被装饰函数
所以,此时我们在上面的代码最后加上一行,调用house函数,实际上就相当于是调用了inner函数
def decorate(func): #装饰器接收一个函数作为入参
print('外层打印测试')
def inner(): #内部函数
func() #调用接收的函数
print('-------刷墙-------')
print('内层加载完成……')
return inner #返回内部函数名
@decorate #装饰器
def house(): #被装饰函数
print('我是毛坯房')
house()#调用house,等价于调用inner
运行结果:
外层打印测试
内层加载完成……
我是毛坯房
-------刷墙-------
2.再来看另外一个装饰器,万能装饰器,它可以满足被装饰函数的多种需求
#万能装饰器
import time
def decorate(func):
def inner(*args,**kwargs):#接收任意个数的参数,以及任何个数的关键字参数
print('-------正在校验中-------')
time.sleep(1)
func(*args,**kwargs) #调用被装饰函数
print('-------校验完毕-------')
return inner #返回内部函数名
@decorate
def f1():#无参
print('----f1-----')
@decorate
def f2(time,n):#两个参数
print('----f2----',time,n)
@decorate
def f3(students):#列表
print('----f3----')
for stu in students:
print(stu)
@decorate
def f4(n, id='1901'):#1个参数,1个关键字
print('----f4----',n,id)
a=f1()
b=f2('2019-01-01',2)
c=f3(['lily', 'lucy'])
d=f4(2,id='1902')
运行结果:
-------正在校验中-------
----f1-----
-------校验完毕-------
-------正在校验中-------
----f2---- 2019-01-01 2
-------校验完毕-------
-------正在校验中-------
----f3----
lily
lucy
-------校验完毕-------
-------正在校验中-------
----f4---- 2 1902
-------校验完毕-------
万能装饰器万能的地方在于它可以装饰不同格式的函数,不管被装饰函数传参为无参,列表,还是关键字,都可以在不需要修改装饰器代码的情况下完成不同的功能。
这里主要的功臣就是*args,**kwargs,它表示可以接收任意个数的参数以及关键字。
3.多层装饰器,即给一个函数加多个装饰器的情况,代码如下:
#多层装饰器
#特点:谁距离被装饰函数近就先执行哪个装饰器,装完后再使用下一个装饰器
def decorate1(func):#装饰器1
print('开始装饰1')
def inner_func1(*args,**kwargs):
func(*args,**kwargs)
print('----刷墙----')
return inner_func1
def decorate2(func):#装饰器2
print('开始装饰2')
def inner_func2(*args,**kwargs):
func(*args,**kwargs)
print('----铺地板----')
return inner_func2
@decorate2
@decorate1
def func():
print('我是毛坯房')
func()
运行结果为:
开始装饰1
开始装饰2
我是毛坯房
----刷墙----
----铺地板----
4.带参数的装饰器。之前我们有举例带参数的被装饰函数,所以引出了万能装饰器,如果装饰器也带参数呢?
先来看下带参数的装饰器的特点:
带参数的装饰器的特点
1.3层结构(上面的例子都是2层结构)
2.最外层的函数负责接收装饰器参数
3.里面的内容还是原来装饰器的内容
了解特点后,接着来看一个带参数的装饰器的例子:
#带参数的装饰器
def outer(q):#第一层,负责接收装饰器的参数
def decorate(func):#第二层,负责接收被装饰函数
def inner_func(*args,**kwargs):#第三层,负责接收被装饰函数的参数
func(*args,**kwargs)
print('铺地板{}块'.format(q))
return inner_func#返出来第三层
return decorate#返出来第二层
@outer(q=10)#装饰器带参数q=10
def house(time):
print('我是毛坯房,{}开始装修'.format(time))
@outer(q=100)#装饰器带参数q=100
def street():
print('新修的道路名字叫深南大道')
house('2019-12-21')
street()
运行结果为:
我是毛坯房,2019-12-21开始装修
铺地板10块
新修的道路名字叫深南大道
铺地板100块
跟之前的例子相比,带参数的装饰器多了第3层,用来接收装饰器的参数,其他跟之前的2层结构一致,每层都有各自的职责。
第一层,负责接收装饰器的参数
第二层,负责接收被装饰函数
第三层,负责接收被装饰函数的参数
然后依次会返回各自内存函数的函数名。
装饰器的主要特点差不多介绍完了,关于装饰器的实际应用见《python之装饰器应用》