闭包如何“知道”它需要保留状态信息?

时间:2018-11-26 19:33:50

标签: python python-3.x

我了解闭包的基本知识。我在学习python时遇到的一些问题的常见示例是:

def maker(N):
    def action(X):
        return X ** N
    return action

我了解运行制造商的结果,并且我知道即使制造商封闭了范围,行动仍保留了一些状态信息N。我也了解到N的不同值存储在不同的号召性用语中。但是我不明白的是,解释器如何“知道”在操作中引用了N。

如果一个函数的主体仅在调用该函数时运行,那么解释器怎么可能甚至知道将N的数据与嵌套的动作函数相关联?我想也许当存在这样的嵌套结构时,python可能会在内部查看是否有任何引用。我尝试过:

def f1():
    def f2():
        print(undefined_variable)

如果是python检查嵌套函数以确定它们是否在封闭范围内引用变量的情况,那么当遇到f2中的未定义变量时,它还会抛出错误吗?我的猜测是不会这样做(因为即使在调用f1的情况下也不会在这里吐出错误)。

所以我的问题是,如果那些嵌套函数的主体直到被调用时才执行,那么python如何知道将范围内的名称与嵌套函数相关联?

1 个答案:

答案 0 :(得分:3)

要为@DYZ的答案添加更多细节,请尝试以下区别:

def foo(a):
    return lambda b: a * b

def foo2(a):
    return lambda b: locals()['a'] * b

def foo3(a):
    def bar(b):
        return locals()['a'] * b
        print('not executed', a)
    return bar
  • foo(3)(5)成功评估为15
  • foo2(3)(5)无法评估,因为解析器不“知道”以后将需要a
  • foo3(3)(5)之所以成功,是因为它知道以后需要a,因此建立了一个绑定它的闭包。如果字节码生成更智能,则可能会意识到print无法访问,因此无法构建闭包,但是在Python 3.7中它对我没有作用

dis module可能使Python在幕后所做的事情更加明显,例如:

from dis import dis
dis(foo)

打印出与foo关联的字节码,尝试与其他功能进行比较