你能解释一下闭包在Python中的应用吗?

102 投票
13 回答
19133 浏览
提问于 2025-04-11 00:04

我最近读了很多关于闭包的内容,觉得自己好像明白了,但为了不让自己和别人搞混,我希望有人能尽量简单明了地解释一下闭包。我想要一个简单的解释,帮助我理解在什么情况下以及为什么我会想用它们。

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

撰写回答