首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >装饰器的控制流程

装饰器的控制流程
EN

Stack Overflow用户
提问于 2018-09-09 18:32:50
回答 2查看 349关注 0票数 3

我在理解带有装饰器的Python程序中的控制流方面有困难。

代码语言:javascript
运行
复制
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的新手。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-09-09 19:21:23

语法

代码语言:javascript
运行
复制
@some_decorator
def somefunc():
   ...

相当于:

代码语言:javascript
运行
复制
somefunc = some_decorator(somefunc)

这在Python中是可能的,因为函数是一流对象。它们可以作为参数传递给其他函数,并从其他函数返回--即所谓的高阶函数

在您的示例中,对multiply()的最后调用实际上运行了innerExector(),这是一个由multiply()修饰定义创建的函数。要了解这里发生的事情,请仔细查看executor的定义

代码语言:javascript
运行
复制
def executor(func):
    def innerExecutor():
        #print("inside executor")
        print("------------------------")
        func()
        print("------------------------")
    return innerExecutor

当守则:

代码语言:javascript
运行
复制
@executor
def multiply():
    ...

运行时,将以函数executor作为参数调用函数multiplyexecutor定义函数innerExecutor(),并返回它,但不执行它。innerExecutor()的这个实例被调用来代替将来对multiply()的所有引用。

但是等等--通常,我们不想完全替换正在修饰的函数。innerExecutor()需要在某个时候调用修饰函数。回想一下,修饰函数定义:

代码语言:javascript
运行
复制
@executor
def multiply():
    ...

相当于:

代码语言:javascript
运行
复制
def multiply():
    ...
multiply = executor(multiply)

将要修饰的函数作为参数传递给装饰器,允许innerExecutor()的定义调用它。但是,等待- innerExecutor()是在executor()返回并且它的参数func已经超出范围之后才被调用的。那它为什么起作用呢?

由于Python的另一个特性叫做闭锁。这意味着内部函数可以引用在封闭作用域中定义的局部变量--包括传递到外部函数executor的参数--即使在退出封闭作用域之后也是如此。闭包的神奇之处在于,解释器检测内部函数定义对外部函数的局部变量的依赖,即使在executor()返回之后也保持它可用。这个链接更详细地介绍了闭包。

最后,最后一行中对multiply()的调用实际上调用了在运行修饰定义时创建的innerExecutor()实例,而后者又调用了multiply()的原始未修饰版本。

每次装饰器用于装饰函数定义时,它都会创建内部函数的一个新实例,该实例将替换未修饰的函数。因此,如果装饰5个不同的函数,就会创建5个不同的innerExecutor()实例。稍后,当调用任何这些修饰函数时,它将转而调用适当的innerExecutor()实例,后者反过来调用相应的未修饰函数。

票数 4
EN

Stack Overflow用户

发布于 2018-09-09 19:46:16

它返回innerExecutor()的引用,该引用存储在哪里? 控件何时实际传递给内部函数?

它不是存储在任何地方,它的名称如下:

代码语言:javascript
运行
复制
innerExecutor(multiply)

这就是为什么您的装饰方法需要返回它自己的引用,否则,它将等价于以下内容:

代码语言:javascript
运行
复制
None(multiply)  # TypeError: 'NoneType' object is not callable

以下是上面行为的文档

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52247498

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档