Python装饰器的详解

2022-08-17 14:49:43

现在就来详细讲解一下python的装饰器

装饰器:装饰器本身是用来是为一个函数是实现新的功能,并且不改变原函数的代码以及调用方式。

装饰器的理解比较难,装饰器的使用用到了闭包,闭包是学习装饰器的基础。所以先看闭包:

闭包

# coding:utf-8


def fun():
    def fun1():
        print("i am fun1")
    return fun1     #这个地方返回fun1的内存地址

if __name__ == '__main__':
    f = fun()   #f保存了fun1的内存地址
    f()     #执行f函数就是执行fun1函数
    print("函数fun1的内存地址为:",f)

上面代码中,我们首先执行f = fun()。这里我们先走fun函数,fun()内部有fun1()函数,最终返回fun1的内存地址。

函数定义完后,在全局把fun()赋值给变量f,此时f中拿到的是fun1的内存地址,这时候你可以把f看成是fun1,进行f()操作相当于调用fun1(),所以上面代码的输出结果为:

在这里插入图片描述
这时候你可能会问,f就是fun1,为什么不能直接调用fun1呢,我们可以试试能不能调用:

在这里插入图片描述
因为fun1()是在全局的函数fun()里面定义的,全局情况下只能调用fun(),不可以直接调用fun()里面的函数。

我们要想在全局情况下调用“全局函数”内部定义的函数,就必须令该全局函数返回“内部函数”的内存地址,然后将该内存地址赋值给一个变量,通过调用这个变量来实现“全局调用内部函数”,而此时,这个“内部的函数”就称为“闭包”。

下面就来说说装饰器

第一种:不带参数的装饰器:

这里我们先定义了一个装饰器Fun(),而Fun函数里面的fun1函数就是一个闭包。当我们在函数Main_fun定义前加上@Fun时,这个语句相当于:Main_fun = Fun(Main_fun)。也就是说,我们在进行不带参数的装饰器的调用时,相当于把下面的函数名当做参数传给了@后面的函数,@Fun也就相当于执行了Fun(Main_fun)。后面就好理解了:Fun()函数返回了fun1函数的内存地址,下面的Main_fun()其实就调用了“闭包”fun1(),进行了fun1()函数里面的操作。

# coding:utf-8

def Fun(func):
    def fun1(*args):
        print("我是闭包函数哦~",args)
        func()          #这个函数是传进来的函数,与外界无关
    return fun1  # 这个地方返回fun1的内存地址


@Fun  # 等价于  Main_fun = fun(Main_fun)
def Main_fun():
    print("我是被装饰的函数哦~")


if __name__ == '__main__':
    Main_fun()    #运行这个函数就直接跳到闭包里面去了。这个函数是否执行,取决于闭包里面是否调用
    Main_fun("我是参数")    #传递的参数会被带到闭包里面去接接收参数。

运行结果:
在这里插入图片描述

第二种:带参数的装饰器

在这里插入图片描述
运行结果:
在这里插入图片描述
这里需要注意的是:如果要返回函数的话,带参数的装饰器就要写三层内嵌函数。

带参数的装饰器的具体执行过程分为两步:首先执行Dec(‘QQ’),不管中间过程,Dec函数返回的是函数outer的内存地址,此时就变成了@outer,按照“不带参数的装饰器”的调用过程我们知道,此时outer将函数func2的名称当做是参数执行outer里面的函数inner()。另外我们还需要注意:现在inner里不仅有func2,还有Dec本身所携带的参数’QQ’。

此外:打印出来的"i’m inner"是在判定if type == 'QQ’后直接执行的;而"i’m func2"是inner()函数执行“outer函数所带的参数”调用的结果,也就是说inner函数最后调用了“outer函数所带的参数”func并执行了它,换句话讲,inner就是一个闭包。

  • 作者:杨二K
  • 原文链接:https://blog.csdn.net/qq_40637313/article/details/89228691
    更新时间:2022-08-17 14:49:43