你能解释一下闭包在Python中的应用吗?
我最近读了很多关于闭包的内容,觉得自己好像明白了,但为了不让自己和别人搞混,我希望有人能尽量简单明了地解释一下闭包。我想要一个简单的解释,帮助我理解在什么情况下以及为什么我会想用它们。
13 个回答
24
老实说,我对闭包这个概念理解得很透彻,但我一直不太明白“闭包”到底指的是什么,以及它有什么特别之处。我建议你别再纠结这个词的来源了。
不过,我来给你解释一下:
def foo():
x = 3
def bar():
print x
x = 5
return bar
bar = foo()
bar() # print 5
这里的一个关键点是,从函数 foo 返回的这个函数对象,依然保持着对局部变量 'x' 的连接,即使 'x' 已经超出了作用范围,理论上应该失效。这个连接是指向变量本身,而不仅仅是当时 'x' 的值,所以当调用 bar 时,它打印的是 5,而不是 3。
另外要注意的是,Python 2.x 的闭包功能有限:我不能在 bar 函数内部修改 'x',因为写 'x = bla' 会在 bar 中声明一个新的局部变量 'x',而不是给 foo 中的 'x' 赋值。这是 Python 中赋值和声明的一个副作用。为了绕过这个问题,Python 3.0 引入了 nonlocal 关键字:
def foo():
x = 3
def bar():
print x
def ack():
nonlocal x
x = 7
x = 5
return (bar, ack)
bar, ack = foo()
ack() # modify x of the call to foo
bar() # print 7
49
这很简单:一个函数可以使用它外面环境中的变量,即使控制流程已经离开了那个环境。这最后一点非常有用:
>>> def makeConstantAdder(x):
... constant = x
... def adder(y):
... return y + constant
... return adder
...
>>> f = makeConstantAdder(12)
>>> f(3)
15
>>> g = makeConstantAdder(4)
>>> g(3)
7
注意到在函数 f 和 g 中,12 和 4 分别“消失”了,这个特性使得 f 和 g 成为真正的闭包。
114
对象是带有方法的数据,而闭包是带有数据的函数。
def make_counter():
i = 0
def counter(): # counter() is a closure
nonlocal i
i += 1
return i
return counter
c1 = make_counter()
c2 = make_counter()
print (c1(), c1(), c2(), c2())
# -> 1 2 1 2