Python闭包Closure 2

  由于Python中,变量作用域为LEGB,所以在函数内部可以读取外部变量,但是在函数外不能读取函数内的变量。但是出于种种原因,我们需要读取函数内的变量时候怎么办?那就是在函数内在加一个函数。

1 def outer():
2     x = 5
3     def inner():
4         print(x)
5     return inner
6 
7 a = outer()
8 a()#print 5

这样,我们就可以看到函数内部的变量了。

上面的inner就是闭包,闭包就是能够读取其他函数内部变量的函数,也就是定义在函数内部的函数,在本质上来说,闭包就是连接函数内和函数外的桥梁。同时,闭包也可以理解为可以携带状态的函数,可以用这个特性构建类似于类private变量,携带状态的回调函数等。

闭包有两大作用,一个是像上面的可以读取函数内部的变量,一个是让这些变量的值始终保存在内存中。

 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常驻内存

需要注意的是,返回的函数并没有立马执行,直到调用时候才开始执行。

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]在内存中一直没有执行,一直等到调用才开始执行的,那怎么办?

方法就是用函数的参数绑定循环变量的值,这样无论循环变量的值怎么改变,已经绑定到函数参数的值不会改变

 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

使用闭包时候要注意:

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

参考资料:学习javascript闭包

      Javascript闭包

     Python学习手册p431

     Python Cookbook

原文地址:https://www.cnblogs.com/fcyworld/p/6590834.html