在理解带有装饰器的Python程序中的控制流程时,我遇到了麻烦。
def executor(func):
def innerExecutor():
#print("inside executor")
print("------------------------")
func()
print("------------------------")
return innerExecutor
@executor
def multiply():
n1 = 10
n2 = 20
print("multiplication = ", (n1 * n2))
multiply()
我遇到的麻烦是:调用executor()
函数并返回innerExecutor()
的引用时,该引用存储在哪里?控件何时真正传递给内部函数?我是Python的新手。
答案 0 :(得分:3)
语法
@some_decorator
def somefunc():
...
等效于:
somefunc = some_decorator(somefunc)
这在Python中是可能的,因为函数是first-class objects。它们可以作为参数传递给其他函数,也可以从其他函数返回,即所谓的higher-order functions。
在您的示例中,对multiply()
的最终调用实际上运行innerExector()
,这是由修饰后的multiply()
定义创建的函数。要了解这里发生的情况,请仔细查看executor
的定义:
def executor(func):
def innerExecutor():
#print("inside executor")
print("------------------------")
func()
print("------------------------")
return innerExecutor
输入代码时
@executor
def multiply():
...
运行时,以函数executor
作为参数调用函数multiply
。 executor
定义函数innerExecutor()
,并返回它但不执行。调用innerExecutor()
的这个实例来代替以后所有对multiply()
的引用。
但是等等-通常,我们不想完全替换正在修饰的函数。 innerExecutor()
需要在某个时候调用修饰的函数。回想一下修饰后的函数定义:
@executor
def multiply():
...
等效于:
def multiply():
...
multiply = executor(multiply)
将要装饰的函数作为参数传递给装饰器,从而允许innerExecutor()
的定义对其进行调用。但是,等等-innerExecutor()
直到很久以后才返回,executor()
返回并且参数func
超出范围。那为什么行得通呢?
感谢Python的另一个功能closure。这意味着内部函数可以引用在封闭范围内定义的局部变量-甚至在退出封闭范围之后也包含传递给外部函数executor
-的参数。关于闭包的神奇之处在于,解释器检测内部函数定义对外部函数的局部变量的依赖关系,并使其在executor()
返回后仍保持可用状态。 link进一步介绍了有关闭包的信息。
最后,最后一行中对multiply()
的调用实际上调用了运行修饰定义时创建的innerExecutor()
实例,而该实例又调用了{{1}的原始未修饰版本}。
每次使用装饰器来装饰函数定义时,它都会创建内部函数的新实例,以替换未修饰的函数。因此,如果装饰5个不同的功能,则会创建multiply()
的5个不同实例。稍后,当调用这些修饰函数中的任何一个时,它将改为调用innerExecutor()
的相应实例,而该实例依次调用相应的未修饰函数。
答案 1 :(得分:0)
它返回innerExecutor()的引用,该引用存储在哪里?
控件何时真正传递给内部函数?
它没有存储在任何地方,它的调用方式如下:
innerExecutor(multiply)
这就是为什么您的decorator方法需要返回其自己的引用,否则,它将等效于此:
None(multiply) # TypeError: 'NoneType' object is not callable