一,装饰器定义阶段:
1. 什么是装饰器
器:指的是具备某一功能的工具
装饰:指的是为被装饰器对象添加新功能
装饰器就是用来为被装饰器对象添加新功能的工具
注意:装饰器本身可以是任意可调用对象,被装饰器的对象也可以是任意可调用对象
2. 为何要用装饰器
开放封闭原则:封闭指的是对修改封闭,对扩展开放
装饰器的实现必须遵循两大原则:
1. 不修改被装饰对象的源代码
2. 不修改被装饰器对象的调用方式
装饰器的目标:就是在遵循1和2原则的前提下为被装饰对象添加上新功能
二,装饰器的应用
上面的这张图中outter()的功能就是装饰器,它装饰了index函数,他在没有改变被调用对象的源代码和调用方式的前提下,实现了统计函数运行时间的功能,感官体验好像还是index()的调用。
装饰器升级版:装饰器同时装饰两个函数。下图中outter()函数是装饰器,index函数和home函数是被装饰对象。index()函数(其实是wrapper函数)不需要传参,而home()函数(其实是wrapper函数)需要传参,那么要想外部调用home()(其实是wrapper函数)就需要给定义阶段的wrapper()传形参,比如wrapper(name),然后调用wrapper()阶段才能传实参,但一个装饰器在同时需要兼顾两个函数,一个需要传值,另一个不需要传值,同时调用,就会报错。那么我们该如何解决呢????这时我们就需要对装饰器outter()内部函数wrapper()传入两个参数了叫做*args和**kwargs,众所周知这两个参数的作用(在形参中,这两个参数可以接收实参传来的多余位置参数和关键字参数;在实参中,*args这个参数可以将其后面的元组打散成位置实参给位置形参传值,**kwargs这个参数可以将其后面的字典形式的关键字参数打散,传给形参中的关键字参数),所以上图中index不传参,*args和**kwargs没有接收到多余的参数,形成了一个空的()和空的{},在下面调用func()的时候,func括号中(即index括号中)的*args将空元组打散,**kwarg将空字典打散,就没有什么参数传给index函数了。而home()传了位置实参“egon”,wrapper()形参中的*args默认接收了形参中多余的位置实参‘egon’,将‘egon’存元组的形式,而此时**kwargs还是一个空字典,到下面遇到func(*args,**kwargs),*args将(‘egon’)打散成字符串原封不动的传给了*args,**kwargs的一个空字典被打散没有了。这样两个函数都被装饰上了,添加上了新的功能,也并没有改变原函数的代码,也没改变他们的调用方式。
注意:现在以home函数为例,如果home函数内部有个返回值(return 234),那么加上装饰器outter(),接收outter(home)的返回值,print(res=outter(home)) 返回值是None,因为这里的home()就是wrapper()。
三,装饰器的语法糖
在被装饰函数上面一行加上@+装饰器,即,例如:
@timmer
def func()
表示装饰func()函数,意思是func=timmer(func),func是最原始的那个func的内存地址。
运行原理:
python解释器一旦运行到@装饰器的名字,就会调用装饰器,然后将被装饰函数的内存地址当作参数
传给装饰器,最后将装饰器调用的结果赋值给原函数名
四,import time
装饰器模板
def outter(func):
def wrapper(*args,**kwargs):
#在调用函数前加功能
res=func(*args,**kwargs) #调用被装饰的\也就是最原始的那个函数
在调用函数后加功能
return res
return wrapper
@outter #index=outter(index) #index=wrapper
def index():
print(‘welcome to index page‘)
time.sleep(3)
index()
五,叠加多个装饰器
执行步骤:解释语法的时候,是自下而上(解释@语法的时候),而执行装饰器的时候是自上而下的。
原文:https://www.cnblogs.com/zhangchaocoming/p/11182922.html