@装饰器函数
作用:在很多情况下我们需要扩展现有函数的功能,如果重新写一个函数会很麻烦,函数装饰器的作用就是在不改变现有函数的基础上对其进行合理的扩展
简单例子
首先给出一个简单的例子,我们来分析一下他的执行过程:先执行函数B,因为B是被A所装饰的,所以先进入到A中输出“I’m fun A”,然后执行函数B,输出"I’m fun B",接着返回到A中执行剩余部分,输出"rice",并返回“meat”给B。即执行过程为:
- 将B作为参数传给A函数
- 将A的return返回给B
执行的是装饰器主体A,B只不过是我们对A的一个扩展,最后将扩展的结果返回给B。总的执行过程等价于B = A(B)
# 装饰器函数A
def A(fun):
print("I'm fun A")
fun() # 执行传入的fn参数
print("rice")
return "meat"
# 用A装饰B
@A
def B():
print("I'm fun B")
print(B)
'''
I'm fun A
I'm fun B
rice
meat
'''
通过上述例子发现,被装饰的函数B不再是它本身了,而是提前在print(B)之前,def B()已经被执行了被替换成了一个新的东西,上述例子他被)换成了字符串变量“meat”,如果A的返回是一个函数,那么B就依然是一个函数
带参数的复杂例子
接下来我们看一个复杂的例子,给函数B加上参数。如上述所说,在执行B(“milk”)之前带有装饰器的函数B已经被初始化了,所以会输出“I’m fun A
”和“rice”两句,在函数A中返回的是drink即一个带有一个参数arc的函数,所以函数B就被初始化成了drink的样子,我们在下面输入B(“milk”)的时候就会输出“beverage: milk”
#A 作为装饰器函数
def A(fn):
print("I'm fun A")
def drink(arc):
print("beverage:", arc)
print("rice")
return drink
@A
def B(arg):
print("I'm fun B")
print(arg)
# B("milk")
'''
I'm fun A
rice
beverage: milk # 取消注释B("milk")
'''
上述例子等价于下面程序,二者输出相同,也就是说通过装饰器A修饰B,函数B就被重新定义为A中的drink函数,也就是我们下面调用B函数时,其实调用的是drink函数
#A 作为装饰器函数
def A(fn):
print("I'm fun A")
def drink(arc):
print("beverage:", arc)
print("rice")
return drink
def B(arg):
print("I'm fun B")
print(arg)
B = A(B)
B("milk")
带有多个参数
在定义我们训练的model时,通常会有多个变体,例如Swin-T,Swin-S等等,我们初始化各个模型时需要将修饰器修饰多个model,同时不同的model使用的参数数量可能不同,下面展示多个参数的使用
#A 作为装饰器函数
def A(fn):
print("I'm fun A")
def drink(*args, **kwargs):
fn(*args, **kwargs)
print("rice")
return drink
@A
def B(arg):
print("-----------")
print("I'm fun B")
print(arg)
@A
def C(arg1, arg2):
print("-----------")
print("I'm fun C")
print(arg1, arg2)
B("bb")
C("c1", "c2")
'''
I'm fun A
rice
I'm fun A
rice
-----------
I'm fun B
bb
-----------
I'm fun C
c1 c2
'''