python全栈-Day 12
一、完美的装饰器(纠正装饰器的函数指向)
1、装饰器的前后执行的解释
def wrapper(f):
def inner(*args,**kwargs): #定义函数的时候,属于接收参数,此时 *args,**kwargs聚合为元组,字典
print('装饰在函数前的')
print(args) #args参数本身,依旧是 元组
print(*args)
ret = f(*args,**kwargs) #调用函数的时候,属于使用参数,此时 *args,**kwargs拆分为元组的各元素,字典的各key-value
print('装饰在函数后的')
return ret
return inner
@wrapper #fun = wrapper(fun) #装饰器只是一个传话的媒介
def fun(a,b):
print('fun开始了')
print('a',a)
print('b',b)
return 'fun返回值'
re = fun('wangjing',1234)
print(re)
2、此处添加2个知识点
def wahaha():
'''
一个打印娃哈哈的函数
:return:
'''
print('娃哈哈')
print(wahaha.__name__) #函数的名称的字符串格式
print(wahaha.__doc__) #函数的注释
import os
print(os.path.getsize('web_cache') ) #获取文件大小
3、查看基本的装饰器对 原函数产生的变化
注意结果中的 fun.__name__ 的值已经变成了inner!!!!也就是说虽然添加了装饰器wrapper的功能,但是fun函数已经不存在,而是变成了inner
def wrapper(f):
def inner(*args,**kwargs): #定义函数的时候,属于接收参数,此时 *args,**kwargs聚合为元组,字典
'''
这是inner自己的注释
:param args:
:param kwargs:
:return:
'''
print('装饰在函数前的')
print(args) #args参数本身,依旧是 元组
print(*args)
ret = f(*args,**kwargs) #调用函数的时候,属于使用参数,此时 *args,**kwargs拆分为元组的各元素,字典的各key-value
print('装饰在函数后的')
return ret
return inner
@wrapper #fun = wrapper(fun) #装饰器只是一个传话的媒介
def fun(a,b):
'''
这是fun原来的的注释
:param a:
:param b:
:return:
'''
print('fun开始了')
print('a',a)
print('b',b)
return 'fun返回值'
re = fun('wangjing',1234)
print(re)
print(fun.__name__) #实际上fun的函数名已经变成了inner,因为在全局名字空间中没有fun的函数名,fun作为wrapper的参数存储
4、添加一个第三方的装饰器,使fun函数完全不变化,依旧是他本身。即在inner函数上添加 一个第三方的带参数的装饰器
from functools import wraps
def wrapper(f):
@wraps(f) #是一个第三方的装饰器,作用是 完全不改变fun的本质,但是依旧可以实现装饰器wrapper的功能
def inner(*args,**kwargs): #定义函数的时候,属于接收参数,此时 *args,**kwargs聚合为元组,字典
'''
这是inner自己的注释
:param args:
:param kwargs:
:return:
'''
print('装饰在函数前的')
print(args) #args参数本身,依旧是 元组
print(*args)
ret = f(*args,**kwargs) #调用函数的时候,属于使用参数,此时 *args,**kwargs拆分为元组的各元素,字典的各key-value
print('装饰在函数后的')
return ret
return inner
@wrapper #fun = wrapper(fun) #装饰器只是一个传话的媒介
def fun(a,b):
'''
这是fun原来的的注释
:param a:
:param b:
:return:
'''
print('fun开始了')
print('a',a)
print('b',b)
return 'fun返回值'
re = fun('wangjing',1234)
print(re)
print(fun.__name__) #此时fun的函数名依旧是本身的fun
二、带参数的装饰器
给个场景:给函数计算执行时间,之后可能又把这些装饰作用在全部函数中删除
1、先写一个函数:不包含集体删除的功能,写一个装饰器可计算函数执行时间
import time
def timer(func):
def inner(*args,**keargs):
start = time.time()
ret = func(*args,**keargs)
end = time.time()
print(end - start)
return ret
return inner
@timer
def wahaha():
time.sleep(0.1)
print('wahaha')
@timer
def shuangww():
time.sleep(0.2)
print('shuangww')
wahaha()
shuangww()
2、再写一个函数:包含集体删除的功能,写一个装饰器可计算函数执行时间,并且可以通过一个布尔变量的值 控制是否进行删除的功能
import time
flag = False
def timer_out(flag):
def timer(func):
def inner(*args,**keargs):
if flag:
start = time.time()
ret = func(*args,**keargs)
end = time.time()
print(end - start)
return ret
else:
ret = func(*args,**keargs)
return ret
return inner
return timer
@timer_out(flag) #装饰器的 函数名=括号,则代表函数执行,先执行函数(timer = timer_out(flag))再进行装饰器操作(实际上等于 @timer,即wahaha = timer(wahaha))
def wahaha():
time.sleep(0.1)
print('wahaha')
@timer_out(flag)
def shuangww():
time.sleep(0.2)
print('shuangww')
wahaha()
shuangww()
3、最后凑数总结一下逻辑走向
在1中的装饰器的外层再加一个函数,该函数有一个 参数flag,返回值为 timer函数~~
装饰器的装饰方式改为:@timer_out(flag)
装饰器的 函数名=括号,则代表函数执行,先执行函数(timer = timer_out(flag))再进行装饰器操作(实际上等于 @timer,即wahaha = timer(wahaha))
三、多个装饰器装饰一个函数
def wrapper1(func): #func-->innner2
def inner1():
print('inner1:before func')
func() #f
print('inner1:after func')
return inner1
def wrapper2(func): #func-->f
def inner2():
print('inner2:before func')
func()
print('inner2:after func')
return inner2
@wrapper1
@wrapper2
def f():
print('f被执行了')
f()
最后凑一下逻辑走向:
1、把wrapper1放到内存里
2、把wrapper2放到内存里
3、处理装饰器,按照从上到下的执行原则,走到@wrapper1,但是装饰器必须得找到距离最近的函数才能真正发生作用,因此走到了@wrapper2,即
f = wrapper2(f)== inner2
此时wrapper1的形参func指向了f
4、之后由于最近的函数已经找到了,所以再执行@wrapper1,此时f已经指向inner2了,此时所以
#f = wrapper1(f)-->wrapper1(inner2)== inner1
此时wrapper2的形参func指向了inner2
5、此时走到了f(),即调用f函数,此时f函数已经指向了inner1,最终的执行是 inner1,注意执行的inner1中的func函数指的是 inner2,所以最终执行结果是:
inner1:before func
inner2:before func
f被执行了
inner2:after func
inner1:after func
注意:装饰器的部分就只是各自指来指去,只有到f()才有真实的执行,才有了打印结果,也就是说最终只执行了一个部分:inner1,其中inner1使用了一个 上层局部变量:func,对应func指的是 inner2。三层的装饰器就类比即可,所以只记现象就可以了
使用场景:比如想要写两个装饰器,1记录用户登录情况,2计算登录函数执行时间,这个时候2一定作为前一个装饰器
再以上基础上把装饰器的返回值加上,结果返回值用的是 f的哟“hahaha”
def wrapper1(func): #func-->innner2
def inner1():
print('inner1:before func')
ret = func() #f
print('inner1:after func')
return ret
return inner1
def wrapper2(func): #func-->f
def inner2():
print('inner2:before func')
ret = func()
print('inner2:after func')
return ret
return inner2
@wrapper1
@wrapper2
def f():
print('f被执行了')
return 'hahahha'
print(f())

浙公网安备 33010602011771号