详解Python闭包及其中隐藏的陷阱。
什么是闭包?
其实我们在使用函数过程中不经意间就会触发闭包,因为总会出于某种原因会在一个函数内部再定义一个函数,而当内层函数引用了外层函数命名空间内的变量(或者说对象),这时就会触发闭包。
那么什么是闭包?闭包就是对内层函数和其内部引用的上层局部命名空间变量的一种封装。
我们说触发了闭包规则的函数叫做闭包函数
闭包的应用方法:通过外层函数把闭包函数对象(python一切皆对象,函数也是对象)赋值给全局变量,然后通过调用全局变量来调用闭包。
闭包特点:闭包函数会把其定义时引用的外层函数的变量名保存起来,并且这些变量名将不再依存于外层函数,也就是说即使外层函数被删除了这些变量名依然存在。
划重点:上面这段话其实隐藏着一个“坑”,你要记住,闭包保存的仅仅是变量名,并没有立刻保存该变量指向的值,因为有的时候引用的变量值是在变化的,在闭包被调用之前,它引用的不是变量指向的具体值,只有在闭包被调用的时候,它才会去查找这些变量的值!
外层函数将闭包函数对象赋值给全局变量的操作可以通过return直接返回执行,当然也可以不用return,通过其他方法。
首先看一个使用return返回赋值的例子:
从下面输出结果可以看出,即使删除了函数func1,理论上应该消失的变量a依然可以使用(理论上a对应的局部空间消失了,则a应消失),变量a之所以仍然可以被引用,是因为闭包规则的作用,外部函数的局部变量可以被内部函数引用,即使外部函数已经返回了。
其实函数本身也是对象,而对象又有很多属性,其中和闭包相关的就是 、__closure__ 属性。
__closure__ 属性定义的是一个包含 cell 对象的元组,其中元组中的每一个 cell 对象用来保存作用域中变量的值。
触发闭包后,实现了引用上层局部命名空间变量的同时又不依赖于该局部空间,即使该变量所在的函数被删除了,闭包函数依然可以使用它,实际上闭包函数把它保存在了__closure__属性中。
然后我们来看看不用return的例子: