定义
在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。
在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例
Tips:
这里简单的说明一下单独是使用add
是属于函数名称或者说函数的引用,如果函数后面带括号,如add()
这个属于函数的调用。
如何编写闭包函数
那如何写一个闭包函数呢?
其实也是有规律的,就是 外层函数的返回值是里层函数的函数名 。
最后载通过一个例子进行说明。
如果我们要计算一个表达式的值,比如:a*x+b=y
首先我们要考虑最外一层函数的变量,然后是里层函数的变量,接着是里层函数的返回值。
a=3,b=5
x=10,y=?
比如,我们计算的时候,在给出a,b的值后,还需要知道x的值,才可以计算出y的值
那根据这样的一个计算顺序,我们可以确定:外层函数的变量是(a,b),里层函数的变量是 x ,里层函数的返回值就是我们要计算的结果 :a*x+b=y
闭包作用
个人认为使用闭包的好处,就是减少了全局变量的使用,在闭包中环境变量可以持久保存相当于全局变量,在编码中应该要减少使用全局变量。其次使用闭包,可以实现轻量级的接口封装,提高代码可复用性,比如:
def line(a, b):
def xy(x):
return (x,a*x + b)
return line
- 1
- 2
- 3
- 4
- 5
这个函数实现了对求一次函数的定义和求坐标的封装,我们可以通过line定义一个一次函数(line1=line(4,5)),然后通过line1(x)打印出坐标,与普通函数相比我们不需要频繁地传入a,b,x这些参数
闭包的注意事项
def sum1(a):
def sum2(b):
return a+b
return sum2
n1=sum1(23)
n2=sum1(22)
print(n1)
print(n1(2))
def sum2(a):
return lambda x: a*x
l1=sum2(3)
print(l1(4))
def line(a, b):
def xy(x):
return (x,a*x + b)
return xy
k1=line(2,3)
print(k1(1))
def cp():
a=20
def c1(x):
nonlocal a
a=10
b=5
return a*x+b
return c1
print(cp()(2))
print(cp().__closure__)
print((cp().__closure__[0].cell_contents))