有人可以解释一下这段Python代码吗?

时间:2010-07-31 03:22:35

标签: python closures

我最近刚开始使用Python并且还没有充分了解它的所有细节,但最近我遇到this post解释了为什么python有闭包,在那里,有一个示例代码是这样的:

y = 0

def foo():
    x = [0]
    def bar():
        print x[0], y
    def change(z):
        global y
        x[0] = y = z

    change(1)
    bar()
    change(2)
    bar()
    change(3)
    bar()
    change(4)
    bar()

foo()

1 1
2 2
3 3

基本上我不明白它是如何工作的,在这种情况下,x [0]的构造是什么,或者实际上我理解它在做什么,我只是不知道它是怎么回事:)

4 个答案:

答案 0 :(得分:8)

在Python 3中添加nonlocal关键字之前(现在仍然存在,如果因为某种原因你被2.*困住),嵌套函数就无法重新绑定其本地的裸名外部函数 - 因为,通常,对一个简单名称的赋值语句,例如x = 23,意味着x是包含该语句的函数的本地名称。 global存在(并且已经存在了很长时间)以允许分配绑定或重新绑定模块级裸名 - 但没有任何内容(Python 3中的nonlocal除外)我说过)允许赋值在外部函数中绑定或重新绑定名称。

解决方案当然非常简单:因为您无法绑定或重新绑定这样的裸名,所以请使用裸的名称 - 索引或外部命名的某个对象的属性功能。当然,所述对象必须是允许重新绑定索引(例如,列表)的类型,或者允许绑定或重新绑定属性的类型(例如,函数),并且列表通常是最简单和最直接的这个方法。 x正是此代码示例中的列表 - 它只是为了让嵌套函数change重新绑定x[0]而存在。

答案 1 :(得分:5)

如果你看一下我删除全局变量的简化代码,可能会更容易理解:

def foo():
    x = [0]
    def bar():
        print x[0]
    def change(z):
        x[0] =  z

    change(1)
    bar()

foo()

foo中的第一行创建一个包含一个元素的列表。然后bar被定义为打印x中第一个元素的函数,函数change修改列表的第一个元素。调用change(1)时,x的值变为[1]

答案 2 :(得分:4)

这段代码试图解释python何时创建一个新变量,以及python何时重用现有变量。我稍微重写了上面的代码,以便更清楚地说明这一点。

y = "lion"
def foo():
    x = ["tiger"]
    w = "bear"
    def bar():
        print y, x[0], w
    def change(z):
        global y
        x[0] = z
        y = z
        w = z
    bar()
    change("zap")
    bar()
foo()

这将产生此输出:

lion tiger bear
zap zap bear

关键是内部函数更改能够影响变量 y ,以及数组 x 的元素,但它确实如此不要更改 w (因为它获得了自己的本地变量 w ,但未共享)。

答案 3 :(得分:2)

x = [0]创建一个值为0的新列表。 x [0]引用列表中的零eth元素,也恰好为零。

该示例引用了代码中的闭包或可通过的代码块。