因为Python中,变量做用域为LEGB,因此在函数内部能够读取外部变量,可是在函数外不能读取函数内的变量。可是出于种种缘由,咱们须要读取函数内的变量时候怎么办?那就是在函数内在加一个函数。javascript
1 def outer(): 2 x = 5 3 def inner(): 4 print(x) 5 return inner 6 7 a = outer() 8 a()#print 5
这样,咱们就能够看到函数内部的变量了。html
上面的inner就是闭包,闭包就是可以读取其余函数内部变量的函数,也就是定义在函数内部的函数,在本质上来讲,闭包就是链接函数内和函数外的桥梁。同时,闭包也能够理解为能够携带状态的函数,能够用这个特性构建相似于类private变量,携带状态的回调函数等。java
闭包有两大做用,一个是像上面的能够读取函数内部的变量,一个是让这些变量的值始终保存在内存中。闭包
1 def outer(): 2 n = 999 3 def tr(): 4 nonlocal n 5 n = n+1 6 def inner(): 7 print(n) 8 return tr,inner 9 10 tr,a = outer() 11 a()#print999 12 tr() 13 a()#print1000
由于outer为inner的父函数,而inner被赋值给了一个全局变量,这致使inner和inner依赖的outer常驻内存app
须要注意的是,返回的函数并无立马执行,直到调用时候才开始执行。函数
def outer(): acts = [] for i in range(5): acts.append(lambda x:i**x) return acts acts = outer() for i in range(5): print(acts[i](2)) #print #16 #16 #16 #16 #16
输出为五个16而不是咱们想要的结果,为何?性能
就是由于act[i]在内存中一直没有执行,一直等到调用才开始执行的,那怎么办?学习
方法就是用函数的参数绑定循环变量的值,这样不管循环变量的值怎么改变,已经绑定到函数参数的值不会改变spa
1 def outer(): 2 acts = [] 3 for i in range(5): 4 acts.append(lambda x,i=i:i**x) 5 return acts 6 7 acts = outer() 8 for i in range(5): 9 print(acts[i](2)) 10 #print 11 #0 12 #1 13 #4 14 #9 15 #16
使用闭包时候要注意:3d
1)因为闭包会使得函数中的变量都被保存在内存中,内存消耗很大,因此不能滥用闭包,不然会形成网页的性能问题,在IE中可能致使内存泄露。解决方法是,在退出函数以前,将不使用的局部变量所有删除。
2)闭包会在父函数外部,改变父函数内部变量的值。因此,若是你把父函数看成对象(object)使用,把闭包看成它的公用方法(Public Method),把内部变量看成它的私有属性(private value),这时必定要当心,不要随便改变父函数内部变量的值。
参考资料:学习javascript闭包
Python学习手册p431
Python Cookbook