追逐繁星的孩子

お帰りなさい

首页 标签 归档 分类 关于
一段有趣的代码—闭包
日期 2017-09-19   |    标签 Python   |    评论

今天看到一段比较有意思的代码

L = [ lambda x=x:x for x in range(10) ]
print( [ i() for i in L ] )

其实分析下还算简单:L 是一个 lambda 函数组成的列表,后续只是遍历 L ,分别执行各个lambda函数而已,随即得出结果

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

貌似仅仅这样并没有啥意思哈!

有意思的来了,又有人提了一段代码

L = [ lambda :x for x in range(10) ]
print( [ i() for i in L ] )

我们会碰到下列的迷惑

我们期望结果 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

实际运行结果 [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]

我当时也是一脸懵逼。之后听了群里大神的讲解,也算是豁然开朗。

首先让我们看下第二段代码:L 列表内部是 lambda 函数没问题,此 lambda 函数没有输入,只返回 x 的值。第一点,我们要清楚,在 L 列表形成过程中,lambda 函数是没有执行的,那么我们可以这样表达形成的 L 列表:

[ lambda:x,lambda:x,lambda:x,lambda:x,... ] (太长不写了)

那么假如我们现在开始遍历列表了,我们取出 lambda:x ,返回 x 。那么 x 是多少呢?很明显,之前在列表推导式中我们已经将 x 遍历到了9,所以 lambda:x 返回 9 。没问题!

我们再来看下之前第一段代码:L 列表同样是 lambda 函数组成,不同的是 lambda 函数不同。lambda x=x:x ,该函数输入 x ,输出 x ,默认值为 x (这里其实容易混淆,把输入参数定义为非 x 可能更容易理解)。我们也表达下形成的 L 列表:

[ lambda x=1:x,lambda x=2:x,lambda x=3:x,lambda x=4:x,... ] (太长不写了)

这样表达的话,聪明的你就能得出答案了吧。

其实这个内容涉及的是 python 的闭包。列表推导式返回函数,x 是外层列表推导式变量,已返回的 lambda 函数可使用此变量,然后就造成了一系列可能令人困惑的点。