@
banricho 感谢整理,感谢回答。给了我很大灵感
我还是自问自答吧
刚才又看了一会资料。个人的粗糙理解:
以 Python3 的闭包为例:
在我理解,闭包的最大意义就在于
1.保存环境:实际上创造了第三种作用域,内部的变量可以不被回收
2.函数的面向对象:将函数和数据捆绑了起来,第三种作用域内部的函数可以看出私有变量(因为别人访问不到)
a.包装了函数 b.捆绑了变量数据
顺便区分一下,装饰器,偏函数,闭包
函数式编程,这三者真的是纠缠在一起,没搞清楚就会混淆
装饰器,偏函数其实并不是闭包
他们也基本上没有什么关系
他们只是形式上有些相似,就是函数嵌套函数,并且返回函数
把函数当做参数,和当成返回值,这就叫函数式编程,因为可以实现数学上的 f(f(f(x)))这种感觉
装饰器,就是嵌套函数,传入函数 f ,对 f 进行加工,添加一些功能,再返回函数,依然给 f
这个变量就切换指向了
实际上是丢弃了原来的函数,变成了增强函数,这就是装饰器
偏函数,函数的某些变量被固定了
这样子返回的是一个函数,可以在适合的时候, f( ) 起作用
经常用在 GUI ,比如一个按钮,先固定尺寸,颜色主题,等固定的变量,空出一个标题和信号绑定
然后后面合适的时候,不断地绑定
======
下面来讲闭包:
闭包,形式上和上面两个有点像,很接近,其实很不一样
首先,闭包的语法形式上要素是:
1.嵌套函数
2.返回的是函数
3.内部函数,引用外部函数的变量,包括嵌套函数的 f(x)的直接参数 x
如:
def f(x):
....a=1
....def g( ):
........nonlocal a,x
........a += 1
........x += 1
........print("a:{},x:{}".format(a,x))
....return g
s = f(5)
s()
s()
s()
====
输出:
a:2,x:6
a:3,x:7
a:4,x:8
[Finished in 0.1s]
就比如这个例子,内部嵌套函数, g 引用了 x , a
这就算闭包了。
要想解释清楚这个名字,得从调用说起。
s = f(5) #这步调用,其实是生成了一个函数 g( ) ,变量名 g 付给了 s
只有当 s( ) 的时候,才启用
退一步,我们都知道,函数会产生自己的局部作用域,对 s 来讲,就是 g 函数
g 函数产生了自己的作用域,但是 g 函数调用了 a , x 两个变量, a,x 又在 f 中,可是 f 又调用结束了,该回收了
解释器陷入两难,于是,算是特殊情况
于是解释器,生成了一个特殊作用域
介于 全局作用域和 f 的局部作用域之间的,作用域
当你反复调用,生成多个函数,该作用域中 a , x 是彼此独立的,这个比较特别,要记住
想一个封闭的包裹,夹在 f 的局部作用域和 全局作用域之间
这个从属于外部函数 f 局部作用域的变量 a,x ,被函数“封闭”起来了。
被封闭起来的变量的寿命,与封闭它的函数寿命相等
名字起得很形象,夹在中间,作用域封闭起来,称为闭包( Closure )。
封闭的作用域,外界访问不到
还有就是,他是不会被回收的,据说,寿命和函数一样长。
如果你设置变量为累加
反复调用,就会积累数值
这个作用域和不会被回收的变量,就叫做环境
所谓的记住环境,就是这些变量的数值,可以保持
变量被称作自由变量
我没看出哪里自由,高等数学里自由变量的意思是可以是任意值,表示为 C
这里大概的意思是,解释器管不着,不被回收
总结一下闭包,之后的特点:
作用域内的变量
1.不会被回收
2.相对封闭,不会被访问到,想一个封闭的包内的变量
3.反复调用,可以积累
4.for 循环使用的时候,总是以最后一个为准,因为是临解释的时候,才使用
换个角度看闭包:
def f(x):
....a=1
....def g( ):
........nonlocal a,x
........a += 1
........x += 1
........print("a:{},x:{}".format(a,x))
....return g
闭包实际上就是记录了外层嵌套函数的作用域中的变量
通过这个 f , g 例子,可以建立多个自定义函数
这很容易让人联想到面向对象编程
f 更像是 g 的构造器,
a,x 是一个私有变量
数据和变量捆绑,函数版本的面向对象
闭包意味着数据与函数结合起来了,这和面向对象思想中的“对象”的概念很接近。
于是闭包有了各种用途
1.可以返回加强的函数,作为函数工厂函数,比如时间戳装饰器
2.可以贮藏闭包作用域中的变量,可以做一个独立环境的计数器
3.可以构造一个私有变量( JS )
4.记住环境, JS 中,可以带着 DOM 的 div 信息,跟到最新点击信息
5.既然都是面向对象,闭包可以实现的, OOP 都可以实现,反过来
OOP 可以实现的功能,闭包有时候可以化繁为简。