python 变量作用域问题(经典坑)

偶尔看到python的一个经典坑:

flist = [lambda :i for i in range(5)]
for f in flist():
	print(f())

按照一般逻辑,结果应该是 0 1 2 3 4
但运行结果是

4
4
4
4
4

查了一下,主要是变量作用域问题和函数执行的问题。
出现这种情况的主要原因是,循环在python中不形成作用域。也就是说,i不仅仅在for循环内有效,for循环结束后i依然可以被使用,即循环结束后,i=4
比如说,如果这样写:

flist = [lambda :i for i in range(5)]
del i
flist[0]()

就会报错

NameError                                 Traceback (most recent call last)
 in ()
      1 flist = [lambda :i for i in range(5)]
----> 2 del i
      3 flist[0]()

NameError: name 'i' is not defined

因为把i删除了之后,lambda就没办法找到返回值i了。

然后,只有函数在被调用的时候才运行函数内部的东西,也就是说,在遍历flist的时候,每调用一个f,lambda :i 被执行一次,但记住这时候i=4,所以所有f都返回4。

要想达到预期效果,可以稍微修改一下:

flist = [lambda x=i: x for i in range(5)]
for f in flist:
    print(f())

输出结果

0
1
2
3
4

为什么这样就可以了呢?先看下面:

flist=[]
for i in range(5):
    def func():
	    x = i
        return x
    flist.append(func)
flist[0]()

输出结果是0。这段代码和上面是等价的。可以看到,i 的值此时被传递进了函数,也就是说,每一个 func 中都有 i值。等到循环结束,flist中的函数元素被调用的时候,因为 i 值在循环的时候已经成了每个func函数中的局部变量,也就是0 1 2 3 4,所以flist0=0。

你可能感兴趣的:(Tips)