闭包是什么?小菜很难用一句话说明或者用白话文概括。我们先看看其他语言是怎么定义闭包的。
ECMAScript
中给闭包的定义是:闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。
维基上的解释
: 在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
不知道大家看到上面那些概念是什么反应,反正我觉得词很拗口还很难懂,他们站在专业的角度给出闭包的定义。
参考文章:
1.造成闭包的原因
在python中造成闭包的原因,个人认为是作用域造成的。我们用闭包写一个y = 5x + 3
的函数
def closure():
x = 5
b = 3
def curve(a):
return a * x + 3
return curve
y = closure()
>>> y(1)
8
>>> y(2)
13
python 中有全局变量
、局部变量
、类变量
。在函数外部不能访问函数内部变量,但是函数内部可以访问外部变量。上面列子中,我们在cloosure
函数外部是肯定不能访问x
,b
的值。在计算机中,调用函数执行完后就会销毁,当我们调用closure
函数后,返回了curve
函数实体。curve
实体中的x
、b
变量并未被销毁,而是保存了下来。curve
函数就形成了一个闭包,因此x
、b
变量的生命周期被延续下来。
2.为什么使用闭包
闭包避免了使用全局变量,此外,闭包允许将函数与其所操作的某些数据(环境)关连起来。这一点与面向对象编程是非常类似的,在面对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。
一般来说,当对象中只有一个方法时,这时使用闭包是更好的选择。来看一个例子:
def adder(x):
def wrapper(y):
return x + y
return wrapper
adder5 = adder(5)
# 输出 15
adder5(10)
# 输出 11
adder5(6)
比用类来实现更优雅,此外装饰器也是基于闭包的一中应用场景。
所有函数都有一个 __closure__
属性,如果这个函数是一个闭包的话,那么它返回的是一个由 cell
对象 组成的元组对象。cell 对象的cell_contents
属性就是闭包中的自由变量。
>>> adder.__closure__
>>> adder5.__closure__
(<cell at 0x103075910: int object at 0x7fd251604518>,)
>>> adder5.__closure__[0].cell_contents
5