python闭包关于闭包,很多博客是这样解释的:对于嵌套函数,外层函数的返回值是内层函数,内层函数引用外层函数的局部变量在。外层函数执行后,局部变量不会被回收,而是和返回的内层函数一起存在,这种现象称为闭包。但是,以上理解有点繁琐和局限。在计算机科学中,闭包(Closure)的缩写词法闭包(LexicalClosure)是一种引用自由变量的函数。引用的自由变量将与函数一起存在,即使它离开了创建它的环境。因此,还有另一种说法,闭包是由函数及其关联的引用环境组成的实体。也就是说,对于第一段的定义,可以适当放宽一些限制,python中的闭包实现就没有那么限制了。参考通过上面的介绍,可以对python闭包有一个大概的了解,但是一些看似简单的细节还需要进一步细化。Python中的变量概念与C/C++中的非常不同。在C/C++中,变量是一个实体,名字和内存是一体的。改变变量的值不会改变它的内存地址。变量的概念在python中是不适用的,在很多场合下使用会让人迷惑。python中使用的概念是引用和对象,即如果a=123,a是一个引用名,123是存储在内存中的对象值。这其实更像是C/C++中的一个指针和它所指向的内存。可以看出python把语法包裹在了上面。回到前面讨论的闭包这个话题,里面用到了变量的概念,即函数引用的变量会和函数一起存在。这里的变量其实是引用名和内存对象的复合概念。我们在这里进一步明确:函数中使用的外层函数的引用名(指针),其指向的内存对象在外层函数退出后不会被回收,引用名(指针)会与内部函数一起存在,虽然此时引用名(指针)对内部函数来说不是“可见的”。问题defcount():fs=[]foriinrange(1,4):deff():returni*ifs.append(f)returnfsf1,f2,f3=count()print(f1())print(f2())print(f3())对于上面的代码,如果你按照C/C++中的概念来理解python中的变量,你会认为输出依次是1、2、3。其实不然,真正的输出是:3,3,3。根据上一节python中引用和闭包的解释,内存f函数中使用了外层引用名i。虽然在循环中对链表fs添加了不同的f函数,但是都使用了同一个A引用i,引用last对应的值是3。再看一段代码,这段def测试会稍微复杂一点():foriinrange(4):yieldig=test()fornin[1,10]:g=(n+iforiing)print(list(g))以上代码的输出一时不查会以为是11、12、13、14,但真正的结果却是20、21、22、23,让人一时抓不住脑子。首先,for循环中的生成器表达式(n+iforiing)其实本质上是一个函数,写成表达式的形式只是一个语法糖,其函数形式为:defgen(n):#g是外部全局生成器gforiing:yieldn+i,即生成器本身是一个算法或函数,只有在被“调用”时,即for或When等操作list或next都执行了,才会有真正的价值流转。然后,对于上面第二个例子中的代码,当for循环中n=1时,生成器g被重新赋值,但是注意此时它只是一个特殊的函数,n和i此时并没有真正加入.当第二轮for循环n=10时,在(n+iforiing)表达式中调用了g,那么此时流入函数的n的值实际上是10,即g在这次这个generator对应的值为10、11、12、13,也就是这些值都被i引用了。接下来,以与n+i相同的形式创建一个新生成器以重新分配g,并退出循环。自然地,此时g中对应的值为20、21、22、23。
