今天在网上看到一个面试题:
def multipliers():
return [lambda x,y=i: y * x for i in range(4)]
print [m(2) for m in multipliers()]
本来以为结果会是[0,2,4,6]
输出结果居然为:[6,6,6,6],也真是666.
感觉很神奇百度了一下,大部分都是从闭包角度讲,感觉云里雾里,例如:
https://blog.csdn.net/xie_0723/article/details/53925076这一篇讲的就比较详细。
但是我还是像我这种python新手还是有点难理解。于是我就想从python推导式与lambda方面分析一下。
下面这个例子与上面的面试题例子运行结果一样:
temp =[lambda x :i* x for i in range(4)]
print [m(2) for m in temp]
首先temp=[]
说明返回的是一个列表,for i in range(4)
说明这是一个推导式(推导式的作用就是由一个旧的列表生成一个满足条件的新列表,推导式讲解见本人python推导式),产生的新列表是四个元素都是(lambda x : i*x)
的列表。
temp =[lambda x :i* x for i in range(4)]
只是声明了这四个匿名函数。
这个新列表目前是:
[(lambda x : i*x),(lambda x : i*x),(lambda x : i*x),(lambda x : i*x)]
,
只有函数名后面加上()函数才会执行例如上例中的m(2),
这时候新列表就变成了:
[(lambda 2 : i*2),(lambda 2 : i*2),(lambda 2: i*2),(lambda 2 : i*2)]
,
程序要运行就还要知道i
的值,这时候就去找i
的值,发现这时候i
已经在for
循环中变成了3,所以最后输出的结果就是[6,6,6,6]了
那如何让结果变为[0,2,4,6]呢,上面的博客里也给了例子:
def multipliers():
return [lambda x,i=i: i * x for i in range(4)]
print [m(2) for m in multipliers()]
这样输出的结果就为[0,2,4,6]了
现在来分析一下这个例子:
同样我们还是先来转换一下;
temp =[lambda x ,i=i:i* x for i in range(4)]
print [m(2) for m in temp]
这样其实还是不好理解,再来转换一下:
temp =[lambda x ,y=i:y* x for i in range(4)]
print [m(2) for m in temp]
单单看这个匿名函数:lambda x ,y=i:y* x
,是不是就是一个求两数之积的匿名函数,并且第二个参数是一个缺省参数,缺省的值为i
,同样我们知道参数的缺省值在函数定义的时候就要被指定下来。
那么这就好理解了,在使用推导式声明四个匿名函数的时候,每一个匿名函数要知道自己的缺省值是什么啊,不然到时候怎么去计算,所以for i in range(4)
每一个i
值都被y
保存下来。
temp =[lambda x ,y=i:y* x for i in range(4)]
生成的四个匿名函数为:
[(lambda x,y=0 : y*x),(lambda x,y=1 : y*x),(lambda x,y=2 : y*x),(lambda x,y=3 : y*x)]
那结果就顺利成章了 就是[0,2,4,6]。
网友评论