在Python学习的过程当中,装饰器是比较难理解的一个应用。本人也在学习期间也遇到不少坑,现将装饰器的基本调用过程总结一下。闭包
首先,装饰器用到了“闭包”,而“闭包”是学习装饰器的基础,因此在讲装饰器以前先将“闭包”的基本概念带你们一块儿回顾一下:函数
现有以下函数:学习
def func(): def func1(): print('i\'m func1') return func1
if __name__ == '__main__': f = func()
f()
print('函数func1的内存地址为:',f)
咱们在函数func()内部定义了另一个函数func1(),最终return的是func1的内存地址。 spa
函数定义完后,在全局把func()赋值给变量f,此时f中拿到的是func1的内存地址,这时候你能够把f当作是func1,进行f()操做至关于调用func1(),因此上面代码的输出结果为:code
此时有些人可能会问:既然f至关于func1,那么为什么不在全局中直接调用func1()呢?答案是不行~由于func1()是在全局的函数func()里面定义的,全局状况下只能调用func(),不能够直接调用func()里面的函数:blog
这里咱们能够看到:"func1 is not defined",由于在全局程序只能调用func(),是找不到func1()的,跟别提调用了。内存
因此,咱们要想在全局状况下调用“全局函数”内部定义的函数,就必须令该全局函数返回“内部函数”的内存地址,而后将该内存地址赋值给一个变量,经过调用这个变量来实现“全局调用内部函数”,而此时,这个“内部的函数”就称为“闭包”。class
而上述例子中,函数func1就是一个闭包。基础
理解了“闭包”的概念后咱们再来看“装饰器”的调用过程:变量
不带参数的装饰器
如上图:这里咱们先定义了一个装饰器Dec(),而Dec函数里面的outer函数就是一个闭包。当咱们在函数func2定义前加上@Dec时,这个语句至关于:func2 = Dec(func2)。也就是说,咱们在进行不带参数的装饰器的调用时,至关于把下面的函数名当作参数传给了@后面的函数,@Dec也就至关于执行了Dec(func2)。后面就好理解了:Dec()函数返回了outer函数的内存地址,下面的func2()其实就调用了“闭包”outer(),进行了outer()函数里面的操做。
带参数的装饰器
这里须要注意的是:若是要返回函数的话,带参数的装饰器就要写三层内嵌函数。
带参数的装饰器的具体执行过程分为两步:首先执行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就是一个闭包。