问题提出
在之前的文章中,我们写了下边的代码:
def func(f):
print("func()")
def func1(*args, **kwargs):
print("front func1()")
f(*args, **kwargs)
print("behind func1()")
return func1
@func
def func2(ch1 = "here",ch2 = " here"):
print(ch1,ch2,"func2()")
@func
def func3(ch = "here"):
print(ch,"func2()")
func2("hello","world")
# func()
# front func1()
# hello world func2()
# behind func1()
func3("hello")
# func()
# front func1()
# hello func2()
# behind func1()
我们本以为会出现程序中的结果,但是最后的运行结果却是:
func()
func()
front func1()
hello world func2()
behind func1()
front func1()
hello func2()
behind func1()
这跟我们预想的结果不同,那这是为什么呢?
装饰器的程序执行顺序
这里我们仍然以上边的程序为例,看一下装饰器的程序执行顺序。
print("frist print")
def func(f):
print("1:func()")
def func1(*args, **kwargs):
print("front func1()")
f(*args, **kwargs)
print("behind func1()")
print("2:func()")
return func1
print("second print")
@func
def func2(ch1="here", ch2=" here"):
print(ch1, ch2, "func2()")
print("third print")
if __name__ == "__main__":
print("__main__")
func2("hello", "world")
执行后的结果为:
frist print
second print
1:func()
2:func()
third print
__main__
front func1()
hello world func2()
behind func1()
我们来看程序的执行顺序,首先是:
print("frist print")
直接输出,这点没有疑问。接着:
def func(f):
上边是函数 func 的函数定义,自然是跳过执行内部语句。接着:
print("second print")
正常输出,没有疑问。接着:
@func
def func2(ch1="here", ch2=" here"):
print(ch1, ch2, "func2()")
这里我们分语句看,首先是:
@func
没有输出,然后是:
def func2(ch1="here", ch2=" here"):
在执行该条语句时,程序进行了跳转:
def func(f):
print("1:func()")
def func1(*args, **kwargs):
print("front func1()")
f(*args, **kwargs)
print("behind func1()")
print("2:func()")
return func1
程序跳转至函数 func 内部,完成装饰器定义。在跳转过程中,会输出:
1:func()
2:func()
但对于函数 func 中嵌套的函数 func1 却并不执行内部语句,只完成函数定义。然后返回函数句柄,跳出该段程序,回到:
def func2(ch1="here", ch2=" here"):
这里,函数继续执行,但却跳过
print(ch1, ch2, "func2()")
直接执行:
print("third print")
if __name__ == "__main__":
print("__main__")
输出:
third print
__main__
然后就到了函数 func2 的执行语句:
func2("hello", "world")
在此语句中,程序执行又发生了跳转,跳转至:
def func1(*args, **kwargs):
print("front func1()")
f(*args, **kwargs)
print("behind func1()")
执行函数体,输出为:
front func1()
接着执行函数 f,其中函数 f 为装饰器定义时的函数句柄,即为函数 func2,因此会发生跳转执行:
print(ch1, ch2, "func2()")
输出:
hello world func2()
重新返回到函数 func1 的语句体中,输出:
behind func1()
再返回到 “__main__” 中,整个装饰器函数运行完毕。
重点就是,在装饰器定义的时候,会将被修饰函数句柄作为参数传递进入装饰器,因此会出现执行函数 func 中的语句的现象,然后返回嵌套函数句柄,完成装饰器定义。而这就是输出结果跟我们预想有所不同的原因了。