-
装饰器函数在被装饰函数定义好后立即执行。多个装饰器的调用顺序是自下往上的。
-
被装饰函数执行时,装饰器的执行顺序是从上往下的。
案例一:
案例脚本:
def wrapper1(f1):
print('in wrapper1')
def inner1(*args,**kwargs):
print('in inner1')
ret = f1(*args,**kwargs)
return ret
return inner1
def wrapper2(f2):
print('in wrapper2')
def inner2(*args,**kwargs):
print('in inner2')
ret = f2(*args,**kwargs)
return ret
return inner2
def wrapper3(f3):
print('in wrapper3')
def inner3(*args,**kwargs):
print('in inner3')
ret = f3(*args,**kwargs)
return ret
return inner3
@wrapper1
@wrapper2
@wrapper3
def func():
print('in func')
func()
# in wrapper3
# in wrapper2
# in wrapper1
# in inner1
# in inner2
# in inner3
# in func
#装饰器函数在被装饰函数定义好后立即执行。多个装饰器的调用顺序是自下往上的。
# 被装饰函数执行时,装饰器的执行顺序是从上往下的。
运行结果:
in wrapper3
in wrapper2
in wrapper1
in inner1
in inner2
in inner3
in func
Process finished with exit code 0
结果分析:
分析
先执行@wrapper3 等于 func = wrapper3(func) ---> 先打印'in wrapper3', 返回 inner3(把这个作为参数传给wrapper2) 【f3 = func】
在执行@wrapper2 等于执行 wrapper2(inner3) ---> 先打印'in wrapper2', 返回 inner2(把这个作为参数传给wrapper1) 【f2 = inner3】
在执行@wrapper1 等于执行 wrapper1(inner2) ---> 先打印'in wrapper2', 返回 inner1
此时func = inner1 【f1 = inner2】
运行func() 等价于执行inner1() ---> 先打印'in inner1' 再执行f1() 【装饰器中wrapper1(f1),实际 wrapper1(inner2),所以f1=inner2 可以理解f1是形参,inner2是实参】
再运行inner2() ---> 先打印'in inner2' 再执行f2() f2=inner3
再运行inner3() --->先打印'in inner3' 再执行f3() f3=func
再运行func() --->先打印'in func'
ChatGPT回答:
这段代码中,装饰器的执行顺序是从下往上执行,即最后一个装饰器先执行,然后依次向上执行。具体的执行顺序如下:
1. wrapper3 装饰器先执行,打印 "in wrapper3"。
2. wrapper2 装饰器接收 wrapper3 装饰后的函数作为参数,打印 "in wrapper2"。
3. wrapper1 装饰器接收 wrapper2 裰饰后的函数作为参数,打印 "in wrapper1"。
4. 最终,func 函数被依次传入 wrapper1、wrapper2、wrapper3 装饰器,形成装饰链,执行顺序为 wrapper3 -> wrapper2 -> wrapper1。
因此,当调用 func() 函数时,会按照上述装饰器的执行顺序,依次执行 inner3 -> inner2 -> inner1 -> func,并打印相应的信息。
案例二:
脚本案例:
# encoding: utf-8
# @File : test10.py
# @Author: wu shaofan
# @Date : 2024/02/09
# @Desc :
from time import sleep, time
def mylog(func):
print("mylog, start")
def infunc2():
print("日志记录, start")
func()
print("日志记录, end")
print("mylog, end")
return infunc2
def cost_time(func):
print("cost_time start")
def infunc1():
print("开始计时")
start = time()
func()
end = time()
print(f"耗费时间:{end - start}")
print("cost_time end")
return infunc1
# mylog(cost_tine(fun2))
@mylog
@cost_time
def func2():
print("func2, start")
sleep(3)
print("func2, end")
func2()
运行结果:
cost_time start
cost_time end
mylog, start
mylog, end
日志记录, start
开始计时
func2, start
func2, end
耗费时间:3.009023904800415
日志记录, end
Process finished with exit code 0
结果分析:
从靠近函数的装饰器开始执行:
先进到cost_time,print("cost_time start"),print("cost_time end"),返回infunc1, 把这个作为参数传给mylog,进到mylog里面, print("mylog, start"),print("mylog, end"),返回infunc2,进到infunc2里面,print("日志记录, start"),运行func(),此时因为参数是infunc1,所以进到infunc1里面,print("开始计时"),运行func(),它的参数是func2,所以进到func2,print("func2, start"),print("func2, end"),再接下去print(f"耗费时间:{end - start}"),把infunc1运行完了,回到infunc2,print("日志记录, end")。
先执行@cost_time 等于 func2 = cost_time(func2) ---> 先打印'cost_time start'和"cost_time end" 返回 infunc1(把这个作为参数传给mylog) func2 = infunc1
在执行@mylog 等于 func2 = mylog(infunc1) ---> 先打印'mylog, start'和"mylog, end" 返回 infunc2
此时 func2 = infunc2
运行func2() 即运行infunc2() ---> 先打印'日志记录, start' 再执行func(),等于执行infunc1() 还没完
进入infunc1() ---> 先打印'开始计时' 再执行func() 等于执行func2() 还没完
进入func2() ---> 先打印'func2, start' 和 "func2, end" 退出func2函数 ,
再回到infunc1() ---> 先打印"耗费时间:{end - start}" 退出infunc1函数
再回到infunc2() ---> 先打印"日志记录, end" 退出infunc2函数
结束
图片比较直观: