我一直在阅读很多关于闭包的内容,我认为我理解它们,但是没有为自己和他人蒙上阴影,我希望有人可以尽可能简洁明了地解释闭包.我正在寻找一个简单的解释,可以帮助我理解我想要使用它们的地点和原因.
封闭关闭
对象是附加方法的数据,闭包是附加数据的函数.
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
它很简单:一个函数引用包含范围的变量,可能在控制流离开该范围之后.最后一点非常有用:
>>> 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
注意12和4分别在f和g内部"消失",这个特征使得f和g适当地闭合.
我喜欢这个粗略,简洁的定义:
可以引用不再活动的环境的函数.
我补充一下
闭包允许您将变量绑定到函数中,而不将它们作为参数传递.
接受参数的装饰器是闭包的常用用途.闭包是这种"功能工厂"的常见实现机制.在运行时通过数据修改策略时,我经常选择在策略模式中使用闭包.
在允许匿名块定义的语言中 - 例如,Ruby,C# - 闭包可用于实现(多少)新颖的新控制结构.缺少匿名块是Python中闭包的限制之一.
说实话,我完全理解闭包,除了我从来都不清楚究竟什么是"闭合"以及什么是"关闭"它.我建议你放弃寻找术语选择背后的任何逻辑.
无论如何,这是我的解释:
def foo(): x = 3 def bar(): print x x = 5 return bar bar = foo() bar() # print 5
这里的一个关键想法是,从foo返回的函数对象保留了一个钩子到局部变量'x',即使'x'已经超出范围并且应该不存在.这个钩子是var本身,而不仅仅是var当时的值,所以当调用bar时,它会打印5而不是3.
另外要明确Python 2.x的封闭性有限:我无法修改'bar'中的'x',因为写'x = bla'会在bar中声明一个本地'x',而不是分配给foo的'x' .这是Python的赋值=声明的副作用.为了解决这个问题,Python 3.0引入了非本地关键字:
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
我从来没有听说过在同一个上下文中使用事务来解释闭包是什么,这里确实没有任何事务语义.
它被称为闭包,因为它"关闭"外部变量(常量) - 即,它不仅仅是一个函数,而是创建函数的环境的封闭.
在下面的示例中,在更改x之后调用闭包g也将更改g中的x值,因为g将关闭x:
x = 0 def f(): def g(): return x * 2 return g closure = f() print(closure()) # 0 x = 2 print(closure()) # 4