Python中使用列表生成式生成多个lambda函数

1、我们使用列表生成式来生成多个匿名函数

for fun in [lambda x:x*i for i in range(3)]:
    print fun(2)

我们期望的返回结果是:

0
2
4

但是实际的返回结果是:

4
4
4

为什么最后生成的函数都是使用i=2这个值。
2、我们使用函数来生成匿名函数

def create_fun(i):
    return lambda :i

a_list = [create_fun(i) for i in range(3)]
b_list = [lambda :i for i in range(3)]

print a_list[0]()
print b_list[0]()
# 0
# 2

从上面的代码可以看出,使用函数生成的匿名函数使用的i变量是我们预期的值,这是为什么呢?
我们看一下运行时的过程:

我们从图中可以看到,使用函数生成的匿名函数中都一个变量i和值的绑定,但是在列表生成式中生成的函数就没有和值进行绑定。
再来看一个例子:

def foo():
    print var

if  __name__ == '__main__':
  foo()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-2-624891b0d01a> in <module>()
----> 1 foo()

<ipython-input-1-a40eeee590ab> in foo()
      1 def foo():
----> 2     print var
      3 

NameError: global name 'var' is not defined
程序会输入这样的异常,说var这个变量没有定义,就是在python函数定义的时候,var变量只是个变量,并没有和值绑定,只有在调用的时候才会去查找这个变量,我们在执行函数的时候由于没有找到这个变量的值就报错了
var = 12
foo()
12

所以上面使用列表生成式生成的匿名函数中,i变量并没有在函数定义的时候就和i变量的值绑定而是在调用的时候去查找i的值,这个时候由于i已经执行变成2,所以调用匿名函数,看到的i变量的值都是2,这也就是为什么所有的函数打印的结果都是一样的原因。
3、解决方法
我们在定义匿名函数的时候可以显示的给它一个默认参数

for fun in [lambda x,i=i:x*i for i in range(3)]:
    print fun(2)
0
2
4

推荐阅读更多精彩内容