python学习笔记 day11 装饰器(二)
语法糖
之前我们使用装饰器时,是为了增加func()函数的功能,有保证func()函数不改变,代码独立性,但是对外还是调用func()函数,然而实现的功能是扩展了之后的,我们是这样做的:
import time def func(): print("哈哈哈哈") def wrapper(f): def inner(): start=time.time() time.sleep(0.01) f() end=time.time() print(end-start) return inner func=wrapper(func) func()
上面的那句func=wrapper(func)其实可以不用写,而是在被装饰函数func()的上面加上@装饰器函数的函数名
import time def wrapper(f): #装饰器函数 def inner(): start=time.time() time.sleep(0.01) f() end=time.time() print(end-start) return inner @wrapper #在被装饰函数的上面(紧挨着)加上@装饰器函数名 效果等同于下面的func=wrapper(func) def func(): #被装饰的函数 print("哈哈哈哈") # func=wrapper(func) func()
这样就更明显了,直接就好像仍然是调用了func()函数,却好像对原来的func()函数功能进行了扩展;
被装饰的函数func()带有返回值
import time def wrapper(f): #装饰器函数参数为被装饰函数的函数名 def inner(): start=time.time() time.sleep(0.01) ret=f() end=time.time() print(end-start) return ret return inner @wrapper def func(): return '哈哈哈哈' #被装饰函数带有返回值 ret=func() #是有返回值的 print(ret)
程序执行过程:
被装饰函数带有一个参数
import time def wrapper(f): def inner(a): start=time.time() time.sleep(0.01) ret=f(a) end=time.time() print(end-start) return ret return inner @wrapper def func(a): print(a) return "哈哈哈哈" # func=wrapper(func) #相当于语法糖@wrapper ret=func(1) print(ret)
运行结果;
但是如果我有很多个函数都需要使用同一个装饰器函数wrapper,但是这些函数参数个数还不一样,这就需要使用之前提到的动态参数啦:
被装饰函数带有*args动态参数(被装饰的函数的参数虽不确定,但都是按照位置传的参数,需要用到动态参数*args)
import time def wrapper(f): def inner(*args):#因为这里的inner其实就是func1,因为func1=wrapper(func1) start=time.time() time.sleep(0.01) ret=f(*args) #这个f也是func1 因为wrapper(func1) 这个func1就传给了f,而且fcun1是有返回值的,需要有一个变量接收 end=time.time() print(end-start) return ret #inner()函数是需要有返回值的,因为inner就是func1 而func1是有返回值的 return inner #wrapper()函数也是有返回值的 @wrapper #@装饰器函数的函数名,写在被装饰的函数上方(紧挨着) def func1(a,b): #该被装饰的函数有两个参数 print(a,b) return "哈哈哈哈" @wrapper def func2(c): #该被装饰的函数有一个参数 print(c) return "嘻嘻嘻" #func1=wrapper(func1) # func2=wrapper(c=func2) ret1=func1(1,2) print(ret1) ret2=func2(3) print(ret2)
运行结果:
如果被装饰的函数参数个数不确定,且可能需要按照位置传参,也有可能是按照关键字传参,这时候需要考虑动态参数 *args 和**kwargs 一起作用!
被装饰函数带有*args,**kwargs动态参数(被装饰的函数的参数不确定,按照位置或者关键字传的参数,需要用到动态参数*args和**kwargs)
import time def wrapper(f): def inner(*args,**kwargs): start=time.time() time.sleep(0.02) ret=f(*args,**kwargs) #因为被装饰的函数是有返回值的 end=time.time() print(end-start) return ret #inner()函数是有返回值的(因为inner=func1 func1()函数有返回值) return inner #装饰器函数返回被装饰的函数名 @wrapper def func1(a,b,c=1): #被装饰的函数参数个数不确定,有可能按照位置或者关键字传参 print(a,b) print(c) return 'hhhh' #而且被装饰的函数还有返回值 @wrapper def func2(a,b,c,d=1,e=2,r=4): print(a,b,c) print(d,e,r) return "xixixi" # func1=wrapper(func1) #相当于@wrapper # func2=wrapper(func2) ret1=func1(1,2,c=3) ret2=func2(1,2,3,r=3,d=2,e=6) print(ret1) print(ret2)
运行结果::
装饰器函数的固定模板:
def wrapper(f): #装饰器函数的参数就是被装饰函数的函数名 def inner(*args,**kwargs): #该inner就是func 因为语法糖@wrapper=func=wrapper(func) 所以func=inner=f """被装饰的函数之前完成的操作""" ret=f(*args,**kwargs) #因为func()被装饰的函数带有返回值 """被装饰的函数之后完成的操作""" return ret #因为inner=func 而func()函数带有返回值,所以inner()函数也得有返回值 return inner @wrapper #@装饰器函数的函数名,放在被装饰的函数上方 def func(a,b,c=2,f=3,g=4): #被装饰的函数参数个数不确定,按照位置或者关键字传参; print("被装饰函数内部各种相关操作") return '被装饰的函数带有返回值' @wrapper def func2(a,m=2,k=3): #另一个被装饰的函数,可是位置参数只有一个,关键字参数只有两个,这时候inner(*args,**kwargs)就很有用了 print('被装饰的函数内部相关操作') return "func2函数的返回值" #func=wrapper(func) #相当于上面的@wrappper #func2=wrapper(func2) #@wrapper func(1,2,c=100,f=300,g=890) #按照关键字传参时,名字得对应啦!! func2(1,m=100,k=300)
talk is cheap,show me the code