装饰器,如何创建,何时使用,一文搞懂

88 阅读3分钟

介绍

首先我们需要知道装饰器是干什么的,有什么用

我个人的理解是装饰器可以在函数执行之前或执行之后做一些需要做的事,就像中间件一样,最简单的例子,冰箱放大象,

三步走,开冰箱——放大象——关冰箱,但是我们放大象这个步骤很麻烦,可能要捉到大象,驯服大象,让其安全进入冰箱等等操作,而这些操作我们封装成了一个放大象的函数,但是如果我们放猴子,放小狗呢,是不是都要开和关冰箱,那我们就需要用到装饰器了。

小例子

我们通过一个例子先初步了解装饰器

  • 们有这么一个函数,我们调用它返回两个东西,一个输出字符串,一个value的值
def fun1():
    print("大象进去啦")
    value = 666
    return value


value = fun1()
print(value)

// 输出结果
大象进去啦
666
  • 我们现在有这么一个需求,需要在value的值打印输出上面下面分别加上before和after,该如何操作
def outer(fun):
    def inner():
        print("打开冰箱")
        value = fun()
        print("关闭冰箱")
        return value

    return inner
    
fun = outer(fun1)
result = fun()
print(result)

// 运行结果
打开冰箱
大象进去啦
关闭冰箱
666

看完这个例子,可能有些人可能会感觉怪怪的,为什么数字最后输出呢?

上面我们的操作是通过一个outer也可以认为是包裹的一层函数和inner内部被包裹的一个函数组成,我们将函数当作参数传入,其中结构一目了然,我们不就是将fun定义成inner函数并执行了嘛,那就好说了,我们就可以在函数执行前后做出自己的部分操作。然后为什么数字在最后呢,因为result就是value,那最后就相当于输出value。

优化方法

我们有了解决方案,但是是不是稍显复杂呢,每次执行都要调用再调用,能不能只调用一次呢,并且别的函数使用时很方便呢,那就用@符号

@函数
def xxx():
    pass
    
// 函数会自动执行,并将xxx作为参数传入即
xxx() = 函数(xxx)

优化后

优化后,我们发现我们直接调用自定义的函数即可,装饰器函数我们可以将其封装然后复用

def outer(fun):
    def inner():
        print("打开冰箱")
        value = fun()
        print("关闭冰箱")
        return value

    return inner


@outer  # fun1 = outer(fun1)
def fun1():
    print("大象进去啦")
    value = 666
    return value


result = fun1()
print(result)

带参函数装饰器

我们必须考虑到传参问题,就像我们要放大象,放哪个呢,总不能随便就一个吧,这就需要传参

def outer(fun):
    def inner(*args, **kwargs):
        print("打开冰箱")
        value = fun(*args, **kwargs)
        print("关闭冰箱")
        return value

    return inner


@outer
def fun1(a1, a2):
    print("大象进去啦")
    print("a1+a2=", a1 + a2)
    value = 666
    return value


fun1(11, 22)


// 输出结果
打开冰箱
大象进去啦
a1+a2= 33
关闭冰箱