在了解闭包之前,让我们简单了解下内存逻辑状态。内存空间在逻辑上分为三部分:代码区、静态数据区和动态数据区,动态数据区又分为栈区和堆区
下图展示了基本的变量在内存中的逻辑关系:
说明:堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(方法的参数传递时很常见),则这个对象依然不会被销毁,只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。
有了以上的基础,我们现在对闭包进行详细的了解,闭包的本质是一个函数,而这个函数引用了上层局部命名空间的变量。
自由变量:未在本地作用域中定义的变量,例如:定义外层函数内被内层引用的变量
闭包:是一个概念,出现在嵌套函数中,指的是内层函数引用到了外层函数的自由变量,就形成了闭包,很多语言中都有这个概念,在Python中常见于装饰器中
让我们来看个例子:
def outer():
c = [1]
def inner():
c[0] =+ 1 #这一行会报错吗?
return c[0]
return inner
foo = outer()
foo()
foo()
运行结果:
为什么会出现以上结果,这是因为outer函数的执行结束后,outer的引用为0,刚释放了相应的堆栈空间,但C[0]仍被内层的inner引用,这时C[0]就r被保留了在了栈内,当Inner被调用时,便可以使用c[0]的值
我们可以看粗略的看下闭包的图示过程,但下图仅供了解基本原理:
2.然后outer函数返回,foo变量名指向了内部inner函数。这时虽然Outer的运行空间被释放。
但由于函数加载的时候inner内使用了C[0],这样的话,在outer释放的时候,将c[0]与Inner进行了绑定,也就是说,C的引用计数不为0,这样它在堆栈内就未被释放 ,从而当我们在inner执行多次时,C[0]的值一直可以被使用,直到c[0]使用完成,引用计数为0被释放
以上内容均为个人学习理解,如有不正确,还请指正,如果有转载请注明出处。