在Python闭包中记住的值和从内存中消失的范围

在Python闭包中记住的值和从内存中消失的范围,python,closures,Python,Closures,下面是我在教程中找到的一段简单代码 我发现了闭包的一个很好的定义:“一个函数对象,它记住封闭作用域中的值,而不管这些作用域是否仍然存在于内存中。” 我认为下面的rotate()是一个结尾。请帮助我理解,即使在它们的作用域从内存中消失之后,它还记得哪些值(为什么它们的作用域会离开内存) (更新)第2部分:为什么下面的(无闭包)代码不起作用 def make_rotater(seq): val = seq.pop(0) seq.append(val) return val

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

我发现了闭包的一个很好的定义:“一个函数对象,它记住封闭作用域中的值,而不管这些作用域是否仍然存在于内存中。”

我认为下面的
rotate()
是一个结尾。请帮助我理解,即使在它们的作用域从内存中消失之后,它还记得哪些值(为什么它们的作用域会离开内存)


(更新)第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
def make_旋转器(序列):
val=序列pop(0)
序号附加(val)
返回值
r=制造旋转器([1,2,3])
r()
#文件“”,第1行,在
#TypeError:“int”对象不可调用

它会记住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的rotate方法,因此您离开make_rotater时,除了seq之外,不需要它的内存(因为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

这个定义有点对,有点错。这取决于你所说的作用域“仍然存在于内存中”是什么意思。我认为更好的定义应该是“一个函数对象,它记住封闭作用域中的变量,而不管这些作用域是否仍然存在于调用堆栈中。”

调用
make_rotater
时:

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

rotate
闭包使
seq
变量保持活动状态,即使执行离开了
make\u rotater
的范围。通常,当执行离开一个函数时,它的局部变量将不再存在。

没有必要从问题中改变示例;函数参数也是局部变量;
seq
引用的列表是相同的值,尽管
make_rotater
中的本地名称
seq
不再在范围内。是的,但这使它更清晰(因为他也可以从make_rotater外部引用seq,这也将导致seq保留在内存中)我同意,将问题中的示例更改有助于让我更清楚。范围指的是名称,而不是值。
make_rotater
中的名称
seq
引用的列表对象与
rotate
中的名称
seq
引用的对象完全相同。闭包和普通函数之间的区别在于,闭包附加了一个单独的名称空间,其中包含从定义闭包的环境继承的名称,该名称在其全局名称空间之前使用。
def make_rotater(seq):
    def rotate():
        val = seq.pop(0)
        seq.append(val)
        return val
    return rotate