【问题标题】:Remembered values, and scope gone from memory, in a Python Closure在 Python 闭包中记住的值和范围从内存中消失
【发布时间】:2016-04-22 19:29:08
【问题描述】:

下面是我在this 教程中找到的一段简单代码。

这是我发现 here 的 Closure 的一个很好的定义:“一个函数对象,它记住封闭范围内的值,无论这些范围是否仍然存在于内存中。”

我认为下面的rotate() 是一个闭包。请帮助我了解即使在它们的作用域从内存中消失后它还记住了哪些值(以及为什么它们的作用域会离开内存)?

def make_rotater(seq):
    def rotate():
        val = seq.pop(0)
        seq.append(val)
        return val
    return rotate

r = make_rotater([1,2,3])
r()
# 1
r()
# 2

(更新)第 2 部分:为什么下面的(无闭包)代码不起作用?

def make_rotater(seq):
    val = seq.pop(0)
    seq.append(val)
    return val

r = make_rotater([1,2,3])
r()
# File "<stdin>", line 1, in <module>
# TypeError: 'int' object is not callable

【问题讨论】:

    标签: python closures


    【解决方案1】:

    它会记住来自 make_rotator 的本地值,所以如果你这样做:

    def make_rotater():
        seq=[1,2,3]
        def rotate():
            val = seq.pop(0)
            seq.append(val)
            return val
        return rotate
    

    seq被rotate引用,所以当你调用rotate时它会保留在内存中,即使它是在make_rotater中定义的(已经完成,并从内存中清除)

    当您调用 make_rotater 时,它会创建一个新的 seq 并定义引用 seq 的旋转方法,因此您离开 make_rotater 时,除了 seq 之外不需要它的内存(因为 rotate 仍然使用它)。当你不再引用 rotate 时,seq 也会被清理

    第 2 部分:

    你的方法现在不返回另一个方法,它直接返回数字,所以你不需要做 r()

    你可以这样使用它:

    seq = [1,2,3]
    def make_rotater(seq):
        val = seq.pop(0)
        seq.append(val)
        return val
    
    r = make_rotater(seq)
    
    print r # prints 1, note there is no r() just r
    r = make_rotater(seq)
    print r # prints 2
    r = make_rotater(seq)
    print r # prints 3
    

    【讨论】:

    • 问题中的例子不用改;函数参数也是局部变量。
    • 另外,没有从内存中清除; seq 引用的列表是相同的值,尽管 make_rotater 中的本地名称 seq 不再在范围内。
    • 是的,但它更清楚了(因为他也可以从 make_rotater 外部引用 seq,这也会导致 seq 保留在内存中)
    • 我同意从问题中更改示例有助于使我更清楚。
    • 范围是指名称,而不是值。 make_rotater 中名称 seq 引用的列表对象与 rotate 中名称 seq 引用的对象完全相同。闭包和普通函数之间的区别在于,闭包附加了一个单独的命名空间,其中包含从定义它的环境继承的名称,该环境在其全局命名空间之前使用。
    【解决方案2】:

    这个定义有点正确,有点错误。这取决于“仍然存在于内存中”的范围是什么意思。我想说一个更好的定义是“一个函数对象,它在封闭范围内记住变量,而不管这些范围是否仍然存在调用堆栈。”

    当您拨打make_rotater时:

    def make_rotater(seq):
        def rotate():
            val = seq.pop(0)
            seq.append(val)
            return val
        return rotate
    

    rotate 闭包使seq 变量保持活动状态,即使在执行离开make_rotater 的范围后也是如此。通常,当执行离开一个函数时,它的局部变量将不复存在。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-16
      • 2018-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-03
      • 2020-12-17
      • 1970-01-01
      相关资源
      最近更新 更多