系列文章目录
【python之十万个为什么】闭包为什么需要return内层函数
前言
装饰器是python新人比较难以理解的部分。它对格式有较高的要求,比如说,装饰器函数的形参要求是被装饰函数.例如:def decorator(function)#decorator是装饰器,function既是形参,又是被装饰函数。这样严格的要求有什么意义呢?从实际测试结果看,如果不这样,装饰器就会陷入无限死循环状态。
一、装饰器函数形参为什么是被装饰的函数?
首先放入一段正确的代码:
#新装饰器测试—无限循环
def decorator(func):
def wrapper():
func()
return wrapper
@decorator
def func():
print('这是一段正确代码')
func()
这段代码运行结果流畅无误。但如果我们测试,把decorator(func)的形参改个名字呢?
def decorator(function):
def wrapper():
func()
return wrapper
@decorator
def func():
print('我为什么错')
func()
这段代码会出现无限死循环,也就是递归错误。出现这种的原因是什么呢?我们通过代码比较进行分析。
#这是正确代码
def decorator(func):#3
def wrapper():
func()#4
return wrapper
@decorator
def func():#2
print('这是正确代码')
func()#1
正常运行的装饰器中,func函数的传递过程如下:
1.func#1被调用;
2.func()#2开始运行,运行逻辑是decorator(func);
3.上一步中的decorator(func)会根据decorator(func):#3的定义进行下一步操作,等同于启用了一个新函数decorator(func),这个函数的作用是运行wrapper()函数;
4.请注意,这里的func()#4要两部分考虑,它的代码复制func():#2,但逻辑却来自decorator(func):#3。也就是说,func():#2和(func):#3虽然代码一摸一样,但却是两个函数。
#这是错误代码
def decorator(function):#3
def wrapper():
func()#4
return wrapper
@decorator
def func():#2
print('这是错误代码')
func()#1
而在这段错误代码中,因为形参是function,破坏了装饰器的格式。所以func():#2就作为decorator(function)的实参,但仅此而已,后面步骤的内层函数激活和func():#2一点关系都没有。此外,此时的func()#4和func():#2一摸一样,就是一个函数。调用func()#4就是调用func():#2,所以,内层函数会激活func():#2,反过来func():#2会再次作为decorator(function)的实参激活装饰器函数,装饰器函数再调用内层函数并再次激活unc():#2,最终陷入无限循坏的bug中。
总结
简单来说,装饰器函数形参必须是被装饰的函数。只有这样,被装饰函数才能从装饰器中调用。否则,装饰器函数仅仅是激活了内层函数,并没有起到调用被装饰函数的作用。