为什么在python闭包实现中使用单元对象?

时间:2018-11-11 12:21:04

标签: python closures cell

def outer():
    n = 1
    def inner():
        return n
    n = 2
    return inner

inner = outer()
print innner()  # output 2

我很清楚CPython如何实现闭包,我的问题不是为什么输出为2,而是为什么Python将其设计为输出2

python在闭包实现中使用单元对象,它间接引用我们要捕获的PyObject。 PythonVM为一个freevar恰好创建一个单元格对象,在此示例中,在外部范围中,单元格对象首先将ref引用为1,然后将ref引用为2。当我们调用内部函数时,freevar总是在外部函数中加载最新值,因此输出2。

“单元对象”是闭包实现中的附加抽象级别。实际上,我修改了关于STORE_DEREF和LOAD_DEREF操作码过程的CPython代码的几行,删除了“单元对象”级别,将实际对象保存在内部的闭包中。然后该示例将输出1。除了在标准库中进行简单的回溯外,其他所有操作都可以正常进行,某些代码假定单元格是可哈希的。但我认为这不是大问题。

我认为输出“ 1”是直观的。所以我的问题是为什么python在闭包实现中创建“单元对象”级别?我很清楚实现,但是为什么python这样设计?

1 个答案:

答案 0 :(得分:0)

思维模型是,嵌套函数(包括lambda,纯粹是语法上的差异)使用与外部函数相同的变量,因此观察到其,即使在创建函数后也是如此。这很有用:嵌套函数始终是最新的,并且在长函数(包含调用它)中具有分配。但是,这也给循环创建的lambda带来了一个著名的问题:它们全部共享一个循环变量。

此模型的功能与函数捕获值的功能差不多,即:要模拟该模式,您只需创建另一个变量以供嵌套函数使用(这意味着如果涉及到循环,则调用另一个函数),而要使用值捕获来模拟Python的行为,您只需捕获一个容器,该容器的(单个)元素可以更改。

在语法和语言一致性方面,语法应支持哪种行为。这里的决定是使所有读取都是变量。相比之下,C ++即使在一个lambda中也支持两种行为,甚至允许(使用mutable更新捕获值的副本。