一、看代码:
li = [lambda :x for x in range(10)]
res = li[0]()
res:9(所有都是返回9,如res = li[1]() --> 9)
首先,需要解释一些基本知识:
函数在定义的时候,并没有分配内存空间用来保存任何变量的值,只有在执行的时候,才会分配空间,保存变量的值。
然后,这是一个列表解析表达式,每个元素都是一个函数,每个函数返回的是x的值。
所以,这是一个列表,有10个元素,每个元素都是一个函数,函数体是返回x的值,前面说过,没有执行的时候,x是没有值的。
所以,当去执行这个列表中的某个函数的时候,函数就去取这个x的值,那么x的值已经变为9了。因为for循环执行完毕了,x最后变成了9。
循环在python中是没有作用域的概念的,这里的10个函数都会(都可以)引用同一个x(for的那个x),所以在向列表中添加func的时候,并没有保存 i 的值,而是当执行函数( li[0]())的时候才去取,这时候循环已经结束,i 的值是 9,所以结果都是9。即是:li这个列表只是有10个函数,而每个函数体的x变量,引用的都是for的那个x,而for的这个x最后变成了9。
再进一步解释循环的作用域问题:
当 Python 遇到一个变量的话他会按照这样的顺序进行搜索:
本地作用域(Local)→外围作用域——即当前作用域是一个内嵌作用域(Enclosing locals)→全局/模块作用域(Global)→内置作用域(Built-in)。
全局作用域(Global)就是模块内的作用域,他的作用范围是单一文件内。
“for循环内的变量为何可以在for循环结束后继续被访问”:
在7. Compound statements中是这么说的:
The for-loop makes assignments to the variable(s) in the target list.
This overwrites all previous assignments to those variablees including those made in the suite of the for-loop.
…
The target list is not deleted when the loop is finished.
But if the sequence is empty, they will not have been assigned to at all the loop.
也就是说for循环中的target list(for x in range(10) x 就是target list)在循环结束中并未被删除,可以被后续程序直接使用。但除一种情况外:循环序列为空时,target list根本不会被赋值。
PYTHON的作用域由def、class、lambda等语句产生,if、try、for等语句并不会产生新的作用域。变量名引用分为三个作用域进行查找:首先是本地,然后是函数内(如果有的话),之后是全局,最后是内置。
二、也可以按我们预想的返回值:
输出:0 2 4 。就是利用闭包技术,保存 i 的值。
所以,记得:返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变。