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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 116,401评论 15 132
  • 原文链接:https://github.com/EasyKotlin 值就是函数,函数就是值。所有函数都消费函数,...
    JackChen1024阅读 3,030评论 1 15
  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    橘之缘之空阅读 21,785评论 9 114
  • 这个世界, 对着你笑的人太多太多。 真心包容你的, 太少太少。 不后悔,莫过于做好三件事: 一是知道如何选择; 二...
    西廊墨河阅读 93评论 1 0
  • 有没有那么一瞬间,你被自己感动过? 下面两张照片是我在青岛西海岸半程马拉松比赛中最后100米冲刺时摄影...
    破晓时刻阅读 83评论 0 2