装饰器中的控制流

时间:2018-09-09 18:32:50

标签: python decorator

在理解带有装饰器的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的新手。

2 个答案:

答案 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作为参数调用函数multiplyexecutor定义函数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

Here's the documentation of aboves behavior