目录
第八章、函数进阶之装饰器02
一、无参装饰器
1. 什么是装饰器?
装饰器指的是为被装饰对象添加功能,因此定义装饰器就是定义一个函数,只不过是该函数是用来为其他函数添加额外的功能
注意:
- 装饰器本身是可以任意调用的对象
- 被装饰的对象也可以是任意可调用了的对象
2. 为什么要用装饰器
装饰器的实现必须遵循两大原则
不修改被装饰的源代码
不修改被装饰的对象的调用方式
装饰器就是在遵循以上两个原则的前提下被装饰对象添加功能
#真正的装饰器import timedef index(): print('您好啊!') time.sleep(1)def deco(func): # func = 原index '''装饰器''' def f1(): #重新创建后的index start = time.time() func() #原index end = time.time() print(end-start) return f1index = deco(index)index() #f1
3. 怎么用装饰器
第一种传参方式:
def index(): print('welcome to index') time.sleep(1)def time_count(func): # func = 最原始的index def wrapper(): start = time.time() func() end = time.time() print(f"func time is {start-end}") return wrapperf = time_count(index)f()#index = time_count(index) # index为被装饰函数的内存地址,即index = wrapper#index() # wrapper()
welcome to indexfunc time is -1.0008289813995361
下面方式是对第一种的再优化
第二种传参函数:包给函数——外包(指的是再定义命名为原函数的名字的变量,被赋予了原函数的内存地址,再调用被装饰后的函数名字(),以后就可以直接用原来函数的名字调用了)
import timedef index(): print('welcome to index') time.sleep(1)def time_count(func): # func = 最原始的index def wrapper(): start = time.time() func() end = time.time() print(f"{func} time is {start-end}") return wrapper# f = time_count(index)# f()index = time_count(index) # index为被装饰函数的内存地址,即index = wrapperindex() # wrapper()
welcome to indexfunc time is -1.0008289813995361
4. 完善装饰器
上述的装饰器,最后调用index()(实际上是被装饰后的index())的时候,其实是在调用wrapper(),因此如果原始的index()有返回值的时候,wrapper()函数的返回值应该和index()的返回值相同,也就是说,我们需要同步原始的index()和wrapper()方法的返回值。 具体怎么做:
import timedef index(): print('welcome to index') time.sleep(1) return 123def time_count(func): # func = 最原始的index def wrapper(): start = time.time() res = func() end = time.time() print(f"{func} time is {start-end}") return res return wrapperindex = time_count(index)res = index()print(f"res: {res}")
#此处return就已经把原始的index的返回值接收过来了 res = func() end = time.time() print(f"{func} time is {start-end}") return res
welcome to index
<function index at 0x102977620> time is -1.0050289630889893
res: 123
如果原始的home()方法需要传参,那么我们之前的装饰器是无法实现该功能的,由于有timeinner()=home(),所以给timeinner()方法传参即可。
import timedef home(name): print(f"welcome {name} to home page") time.sleep(1) return namedef time_count(func): # func = 最原始的index def timeinner(*args, **kwargs): start = time.time() res = func(*args, **kwargs) end = time.time() print(f"{func} time is {start-end}") return res return timeinnerhome = time_count(home)#就相当于把time_count()的函数返回值(其实是内部函数的地址)赋值给另一个变量名(其实就是被装饰后的原函数的名字)res = home('egon')#调用了timeinner("egon")print(f"res: {res}")
5. 装饰器语法糖
被装饰的函数正上方单独写上@装饰器名
import timedef time_count(func): # func = 最原始的index def wrapper(): start = time.time() func() end = time.time() print(f"{func} time is {start-end}") return wrapper@time_countdef index(): print('welcome to index') time.sleep(1)
welcome to indexfunc time is -1.000335454940796
6. 装饰器模板
#双层装饰器def deco(func): def wrapper(*args,**kwargs): res = func(*args,**kwargs) return res return wrapper
#三层装饰器# 三层装饰器:给双层装饰器加参数def sanceng (engine): def outter(func): def wrapper(*args,**kwargs): # wrapper是未来要运行的函数 #加功能 print(engine) res = func(*args,**kwargs) #func是被装饰的函数 return res return wrapper return outter@sanceng('db')def shopping(): print('shopping')shopping()
二、有参函数
1. 三层闭包
# 三层装饰器:给双层装饰器加参数def sanceng (engine): def outter(func): def wrapper(*args,**kwargs): # wrapper是未来要运行的函数 #加功能 print(engine) res = func(*args,**kwargs) print(res)#func是被装饰的函数 return res return wrapper return outter@sanceng('db')def shopping(x="666"): print('shopping') return xshopping()
dbshopping666