函数装饰器的基本格式,带参数的装饰器,以及多个装饰器同时装饰一个函数

时间:2024-11-18 13:58:32

目录:
1.装饰器的标准格式,及使用方法
2.带参数的装饰器
3.多个装饰器装饰同一个函数

1.装饰器的标准格式,及使用方法
我们在使用函数的过程中,有时在定义好一个函数之后,还想增加一些新的功能,在不改变原函数的情况下,可在原函数的前后增加新的代码。
方法:在定义函数过程中,再定义一个新的函数,通过传参的方法进行嵌套实现功能。
基本语法如下:

def wrapper(func()):
    def inner():
       func() #要装饰的函数
    return inner
  • 1
  • 2
  • 3
  • 4

调用时,利用语法糖@wrapper,在靠近要装饰的函数位置,例如

@wrapper
def test1():
    print("test")
  • 1
  • 2
  • 3

如果需要传参,按照下面的语法格式。

def wrapper(func):
    def inner(*args,**kwargs):
#添加函数调用前代码
        ret=func(*args,**kwargs)
#添加函数调用后代码
        return ret
    return inner
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.带参数的装饰器
假设这样一种应用:我们对多个函数同时使用装饰器,如果因为某种原因,需要暂时取消装饰器,如果函数不多,可以直接注释掉就可以了,但如果很多,就非常的麻烦,这时就可以引入带参数的装饰器,初始参数赋值True,通过修改初始参数,使得装饰器功能失效即可。
实际我们在调用装饰器的时候,上面的代码利用语法糖(@wrapper)是不能对装饰器传参的,所以还要再定义一层函数来实现,方法如下:

fagle=True
def wrapper_outer(fagle):
    def wrapper(func):
        def inner(*args,**kwargs):
            if fagle:
                # 添加函数调用前代码
                ret=func(*args,**kwargs)
                # 添加函数调用后代码
                return ret
            else:
                ret = func(*args, **kwargs)
                return ret
        return inner
    return wrapper
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

实际调用时,语法糖改为@wrapper_outer(fagle)即可

3.多个装饰器装饰同一个函数
当多个装饰器同时装饰一个函数时,会按照嵌套的方式运行,比如下面的代码

def wrapper1(func):
    def inne1r(*args, **kwargs):
        print("装饰器1前代码")
        ret = func(*args, **kwargs)
        print("装饰器1后代码")
        return ret
    return inner1
def wrapper2(func):
    def inner2(*args, **kwargs):
        print("装饰器2前代码")
        ret = func(*args, **kwargs)
        print("装饰器2后代码")
        return ret
    return inner2
@wrapper2
@wrapper1
def test():
    print("test")
test()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

定义wrapper1和wrapper2 两个装饰器,同时装饰test1时,会按照下面的结果进行嵌套输入,结果如下:

装饰器2前代码
装饰器1前代码
test
装饰器1后代码
装饰器2后代码

举个例子,就类似俄罗斯套娃一样,一层层嵌套执行,比较难理解是参数的传递,可以参考下面代码的注释理解。

def wrapper1(func): #  2.调用函数,传参func=test
    def inner1(*args, **kwargs):  #13.执行inner1()
        print("装饰器1前代码")   #14.打印第二行代码
        ret = func(*args, **kwargs)  #15.执行func()等效于执行test(),上面第二步已经传参
        print("装饰器1后代码") #17.执行完func(),打印第三行代码,inner1执行完成
        return ret
    return inner1 #3.返回inner的内存地址,

def wrapper2(func): #=inner1传参
    def inner2(*args, **kwargs):  #10.执行inner2
        print("装饰器2前代码") # 11.打印第一行代码
        ret = func(*args, **kwargs)  #12.执行func()等效于执行inner1() ,因为上面第六步已经为func传参为inner1
        print("装饰器2后代码")  #18.inner1执行完成,继续执行inner2,打印第五行,执行完成
        return ret
    return inner2   # 7. 返回inner2
@wrapper2  # 8.等效于 test=wrapper2(test) 调用wrapper2后,返回inner2,test=wrapper2(test)=inner2
@wrapper1  # 1.最靠近函数,先执行,等效于 test=wrapper1(test) 4调用warpper1后返回inner,test=inner1
def test():
    print("test") #16.执行第三行打印
test() #9.此时执行test()等效于执行inner2()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

前后来回调用比较绕,仔细看下还是能看懂的,实在看不懂,记住结果就好了