@函数装饰器
python
本文字数:877 字 | 阅读时长 ≈ 3 min

@函数装饰器

python
本文字数:877 字 | 阅读时长 ≈ 3 min

@装饰器函数

作用:在很多情况下我们需要扩展现有函数的功能,如果重新写一个函数会很麻烦,函数装饰器的作用就是在不改变现有函数的基础上对其进行合理的扩展

1. 简单例子

首先给出一个简单的例子,我们来分析一下他的执行过程:先执行函数 B,因为 B 是被 A 所装饰的,所以先进入到 A 中输出“I’m fun A”,然后执行函数 B,输出"I’m fun B",接着返回到 A 中执行剩余部分,输出"rice",并返回“meat”给 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 就依然是一个函数

2. 带参数的复杂例子

接下来我们看一个复杂的例子,给函数 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")

3. 带有多个参数

在定义我们训练的 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
'''
4月 06, 2025
3月 10, 2025
12月 31, 2024