Python中的装饰器是基于闭包的基础上的,作用是拓展原来函数功能的一种函数。
什么是闭包呢?
闭包可以简单理解为就是一个嵌套函数,一个外函数和一个内函数并且外函数的返回值是内函数对象。
一个简单的装饰器如下:
def demo(fun):
def inner_func():
print("开始装饰")
fun()
print("装饰完毕")
return inner_func
@demo # 装饰器装饰func函数
def func():
print("hello word")
if __name__ == '__main__':
func()
"""
输出结果===》
开始装饰
hello word
装饰完毕
"""
带参数的装饰器:
def demo(fun):
def inner_func(a, b):
print("开始装饰")
fun(a, b)
print("装饰完毕")
return inner_func
@demo
def func(a, b):
result = a + b
print(result)
if __name__ == '__main__':
func(10, 100)
"""
输出结果===》
开始装饰
110
装饰完毕
"""
注意: 当函数带有参数时,而装饰器不带参数会报错。
在装饰器中,外函数传函数对象,内函数传函数对象的参数。
对于不定长参数的传值可以改为如下示例:
def demo(fun):
def inner_func(*args, **kwargs):
print("开始装饰")
fun(*args, **kwargs)
print("装饰完毕")
return inner_func
@demo
def func(a, b, c):
result = a + b + c
print(result)
if __name__ == '__main__':
func(10, 100, 503)
"""
输出结果===》
开始装饰
613
装饰完毕
"""
对于有多个装饰器的情况:
def demo1(fun):
print("我是demo1")
def inner_func(*args, **kwargs):
print("demo1开始装饰")
fun(*args, **kwargs)
print("demo1装饰完毕")
return inner_func
def demo2(fun):
print("我是demo2")
def inner_func2(*args, **kwargs):
print("demo2开始装饰")
fun(*args, **kwargs)
print("demo2装饰完毕")
return inner_func2
@demo1
@demo2
def func(a, b, c):
result = a + b + c
print(result)
if __name__ == '__main__':
func(10, 100, 503)
"""
输出结果===》
我是demo2
我是demo1
demo1开始装饰
demo2开始装饰
613
demo2装饰完毕
demo1装饰完毕
"""
看这个输出结果是不是有点难以理解?
在有多个装饰器的时候,先自底向上执行装饰器的定义,而后自顶向下执行装饰器的功能。
用堆栈来理解一下,我们知道栈都是(先入后出,后入先出)先自底向上执行装饰器的定义,就是入栈,自顶向下执行装饰器,就是出栈的过程。
我们再来详细分析一下,demo2先装饰func,然后demo1装饰demo2的返回结果,即
test = demo2(fun)
demo1(test)
函数的执行由内向外执行,即先执行括号内的代码块,
demo2(fun) # 执行demo2(fun)
"""
先执行demo2函数内的语句块,即执行print("我是demo2"),
输出: 我是demo2
往下走遇到函数,在Python中,函数是不会自己执行的,除非是有其他语句块调用他,
所以继续往下走,遇到return返回,返回值为demo2的内函数,此时demo2(fun)执行完毕
"""
接下来执行demo1(test)
demo1(test) # 执行demo1(test), 此时的test为demo2的返回值,即demo2的内函数inner_fun2
"""
执行demo1内的代码语句, print("我是demo1")
输出===> 我是demo1
接着往下走遇到函数定义,函数不会自动执行,继续往下走,碰到了return语句,返回值为inner_func
"""
上面执行完之后变成了这样inner_func(test)
inner_func(test) # 执行
"""
执行inner_func函数的代码语句-> print("demo1开始装饰")
输出结果===> demo1开始装饰
往下走遇到了函数调用语句-> fun() 此时的fun则指向test,而test指向 demo2的内函数inner_func2
所以fun() 就是 inner_func2()
进入inner_func2执行里面的代码语句-> print("demo2开始装饰")
输出结果===> demo2开始装饰
往下走又遇上了函数调用语句-> fun(), 此时的fun()则指向 func()被装饰的函数对象
执行func函数的代码语句-> result = a + b + c, 将计算出的值,赋值给result变量
再往下执行-> print(result) 输出语句
输出结果===> 613
func函数执行完毕返回函数调用处
往下走执行-> print("demo2装饰完毕")
输出结果===> demo2装饰完毕
inner_func2()函数执行完毕,返回上一层函数调用处
执行语句-> print("demo1装饰完毕")
输出结果===> demo1装饰完毕
"""
经过这样一波分析是不是对上面的输出结果理解了呢!
总结:
一.装饰器是基于闭包实现的,可以简单理解为(嵌套函数);
二.装饰器的构成:
1.需要一个嵌套函数,也就是说得有一个外部函数,有一个内部函数,内部函数定义在外部函数里面,成为内函数和外函数;
2.内函数点用了外函数的临时变量(一个在外函数中的局部变量)或外函数的参数(形参);
3.外函数返回的是内函数这个函数对象。
三.外函数传函数对象,内函数传函数对象的参数。
四.有多个装饰器时, 先自底向上执行装饰器的定义,而后自顶向下执行装饰器的功能。