我最近刚开始使用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]的构造是什么,或者实际上我理解它在做什么,我只是不知道它是怎么回事:)
答案 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元素,也恰好为零。
该示例引用了代码中的闭包或可通过的代码块。