wraps
其实之前我们看到过,打印被修饰的函数名的时候发现已经不是自己了就是因为,@wrapper 其实就相当于func=wrapper(func) 在全局命名空间中,func已经不是原来定义的func函数了,而是装饰器函数内部的一个闭包函数inner 因为func是wrapper函数的返回值了,原来的func函数已经作为参数传递给wrapper函数的f参数了!
def wrapper(f): def inner(*args,**kwargs): ret=f(*args,**kwargs) return ret return inner @wrapper def func(a,b): print(a,b) return "哈哈哈" print(func(1,2)) print(func.__name__)
运行结果:
其实我们可以借助functools中的wraps 是别人写好的装饰器函数,我们直接拿来用,效果就是可以使得加上装饰器扩充了功能的func函数变得看起来跟之前的调用一样啦:
from functools import wraps def wrapper(f): @wraps(f) #在装饰器函数内部的闭包函数上方加上@wraps(被装饰的函数名) def inner(*args,**kwargs): ret=f(*args,**kwargs) return ret return inner @wrapper def func(a,b): print(a,b) return "哈哈哈" print(func(1,2)) print(func.__name__)
运行结果:
带有参数的装饰器(一个装饰器控制多个函数)
假设我们有一个场景:我们需要为写的众多函数加一个记录函数运行时间的功能,显然,我们可以使用装饰器来实现在不改变原函数功能的前提下,扩充该函数的功能,但是如果某一天,我们不需要记录这些函数的功能了,如果一个一个的删除@wrapper就真的太反人类了。在不需要大费周折的前提下,我们应该如何实现随时增加或者取消扩充函数的功能呢
Flag=1 #是否需要使用装饰器给后续函数增加功能,只需要修改此参数 def wrapper_out(flag): #在原来的基础上增加了一层函数,主要是通过参数flag来控制装饰器函数内部是否给被装饰的函数增加功能 def wrapper(f): def inner(*args,**kwargs): if flag: print("在被装饰的函数之前执行") ret=f(*args,**kwargs) print("在被装饰的函数之后执行") else: ret=f(*args,**kwargs) return ret return inner return wrapper @wrapper_out(Flag) def func1(a,b): print(a,b) return "哈哈哈" @wrapper_out(Flag) def func2(a,b,c): print(a,b,c) return "嘻嘻嘻" print(func1(1,2)) print(func2(2,3,4))
只需要在原来装饰器的基础上在外层扩充一层函数即可,通过传入参数flag来控制是否给原函数增加相应的功能,修改全局命名空间中全局变量Flag的值,Flag=1 行使装饰器函数的功能,Flag=0就是普通的为被装饰的函数执行;
多个装饰器函数装饰同一个函数
如果想给一个函数增加多个不同的功能,我们应该需要为一个函数写多个装饰器:
def wrapper1(f): def inner(*args,**kwargs): print("装饰器1在函数之前执行") ret=f(*args,**kwargs) print("装饰器1在函数之后执行") return ret return inner def wrapper2(f): def inner(*args,**kwargs): print("装饰器2在函数之前执行") ret=f(*args,**kwargs) print("装饰器2在函数之后执行") return ret return inner @wrapper1 @wrapper2 def func(a,b): # 被装饰的函数 print(a,b) return "哈哈哈哈" #func=wrapper2(func) #先看等号右侧,参数func就是全局空间中定义的函数func,传给了wrapper2函数的参数f=func,wrapper2返回的结果是inner 所以等号左边的func就是wrapper2中的inner函数名 #func=wrapper1(func) #先看等号右侧,参数func其实就是上一行等式左边的func,也就是wrapper2函数返回的inner,这个inner作为wrapper1函数的参数f,等号左边的func就是wrapper1函数返回的inner ret=func(1,2) #先看等号右侧,这里的func其实就是上一步wrapper1函数返回的inner,,所以限制性wrapper1函数中的inner函数, print(ret) #最后返回的结果给了等号左侧的ret,最后打印
多个装饰器装饰同一个函数,其实应用场景就是比如一个装饰器记录函数运行时间,另一个装饰器记录函数调用~~~
最后代码的执行过程附图如下: