2011-05-20 54 views
70

为什么以下两个列表解析的输出不同,即使f和lambda函数是相同的?Python:列表解析中的Lambda函数

f = lambda x: x*x 
[f(x) for x in range(10)] 

[lambda x: x*x for x in range(10)] 

你要知道,这两种类型(f)和式(拉姆达X:X * X)返还相同种类。

+0

'[拉姆达X:X * X为在范围X(10)]'快于第一个,因为它没有调用外部循环函数,f代表eatedly。 – riza 2011-05-20 18:50:47

+0

@Selinap:...不,相反,您要通过循环创建一个品牌崭新的功能。 ...和创建这个新功能的开销,然后调用速度稍慢(无论如何我的系统上)。 – Gerrat 2011-05-20 19:00:12

+0

@Gerrat:即使有开销,它仍然更快。但是,当然'[x * x在范围内(10)]'更好。 – riza 2011-05-20 19:13:23

回答

142

第一个创建一个lambda函数并调用它十次。

第二个不调用该函数。它创建10个不同的lambda函数。它将所有这些列入清单。为了让相当于你所需要的第一:

[(lambda x: x*x)(x) for x in range(10)] 

或者更好的是:

[x*x for x in range(10)] 
+5

或'地图(lambda x:x * x,范围(10))',这可能是OP的意思首先。 – 2011-05-20 18:53:16

+0

是的,lambda x:x * x ..(x)似乎是信条。 – staticor 2013-08-19 16:09:48

+0

[lambda x:x * x在范围内(10)] 基本上是haskell中的函数 – 2015-08-29 19:51:42

17

的最大区别在于,第一个例子中实际调用拉姆达f(x),而第二个例子没有。

您的第一个示例相当于[(lambda x: x*x)(x) for x in range(10)],而第二个示例相当于[f for x in range(10)]

7

第一个

f = lambda x: x*x 
[f(x) for x in range(10)] 

运行f()那么它f(x)为每个值

第二个

[lambda x: x*x for x in range(10)] 

在范围内的每个值会运行中的每个值拉姆达该列表,因此它会生成所有这些功能。

2

人民给了很好的答案,但忘了提,我认为最重要的部分: 在第二个例子中,列表理解的X是不一样的lambda功能的X,他们是完全无关的。 因此,第二个实施例实际上是相同的:

[Lambda X: X*X for I in range(10)] 

range(10)内部迭代仅用于在列表生成器10个类似lambda函数(10个独立的功能,但完全类似负责 - 返回每个输入的功率2 )。

。另一方面,第一个例子中的作品完全不同,因为重复的X做的结果进行交互,每个迭代的值是X*X这样的结果将是[0,1,4,9,16,25, 36, 49, 64 ,81]

+0

这是一个重要的观点。我在你的答案中提出了你的建议并详细阐述了它。 – 2015-12-01 13:19:19

36

这个问题倒是很“着名”和“显而易见的”Python语法的一部分发臭 - 优先,lambda或列表理解。

我不认为OP的目的是生成一个从0到9的方块列表。如果是这样的话,我们可以给更多的解决方案:

squares = [] 
for x in range(10): squares.append(x*x) 
  • 这是强制性语法的好醇”的方式。

但是这不是问题的关键。关键是W(hy)TF是否是这种模棱两可的表达方式,所以反直觉?最后我对你有一个愚蠢的例子,所以不要太早拒绝我的回答(我在面试时曾经这样做过)。

因此,OP的理解返回lambda表达式的列表:

[(lambda x: x*x) for x in range(10)] 

这当然只是10个不同平方函数的副本,请参阅:

>>> [lambda x: x*x for _ in range(3)] 
[<function <lambda> at 0x00000000023AD438>, <function <lambda> at 0x00000000023AD4A8>, <function <lambda> at 0x00000000023AD3C8>] 

注意的lambda的内存地址 - 它们都是不同的!

你当然可以有更多的 “最佳”(哈哈)版本的表情:

>>> [lambda x: x*x] * 3 
[<function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>] 

看到了吗? 3次相同 lambda。

请注意,我用_作为for变量。它与lambda中的x无关(它在词法上被掩盖了!)。得到它?

我要离开了讨论,为什么语法优先不是这样,它所有的意思是:

[lambda x: (x*x for x in range(10))] 

这可能是:[[0, 1, 4, ..., 81]],或[(0, 1, 4, ..., 81)],或这是我觉得最合乎逻辑的,这将是1个元素的list - 一个generator返回值。情况并非如此,这种语言不适用于这种方式。

什么,如果...

,如果你不掩盖for变量,并在你的lambda的使用它什么???

好吧,那么废话发生。看看这个:

[lambda x: x * i for i in range(4)] 

这意味着课程:

[(lambda x: x * i) for i in range(4)] 

不过,这并不意味着:

[(lambda x: x * 0), (lambda x: x * 1), ... (lambda x: x * 3)] 

这仅仅是疯了!

列表理解的lambda表达式是在这个理解的范围封闭。一个词汇封闭,所以他们通过参考参考i,而不是它的价值,当他们被评价过!

所以,这个表达式:

[(lambda x: x * i) for i in range(4)] 

大致等同于:

[(lambda x: x * 3), (lambda x: x * 3), ... (lambda x: x * 3)] 

我敢肯定,我们可以看到更多的在这里使用一个Python反编译器(我指的是例如在dis模块),但对于Python-VM不可知的讨论,这已经足够了。 这么多的求职面试问题。

现在,如何制作乘法器lambda的list,它真的乘以连续的整数?那么,同样接受的答案,我们需要通过包装它在另一个lambda,这是越来越称为列表解析表达式打破直接领带i

前:

>>> a = [(lambda x: x * i) for i in (1, 2)] 
>>> a[1](1) 
2 
>>> a[0](1) 
2 

后:

>>> a = [(lambda y: (lambda x: y * x))(i) for i in (1, 2)] 
>>> a[1](1) 
2 
>>> a[0](1) 
1 

(我不得不外的λ可变也= i,但我决定,这是更清晰的溶液 - 我介绍y,这样我们都可以看到哪个女巫是哪个)。

+3

这是一个残酷而不寻常的求职面试问题。 – szeitlin 2015-12-11 17:49:37

+1

我的头烧焦阅读你的答案! – Valilutzik 2016-09-25 17:57:51

+0

如果我的同事没有问,我可能永远不会搜索这个答案 – piggybox 2016-11-10 01:33:43

2

其他的答案是正确的,但如果你试图使功能列表,每一个不同的参数,可以执行,下面的代码将做到这一点:

import functools 
a = [functools.partial(lambda x: x*x, x) for x in range(10)] 

b = [] 
for i in a: 
    b.append(i()) 

In [26]: b 
Out[26]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 

虽然例子是人为的,我认为它是有用的时候想的功能的列表,每个打印不同的东西,即

import functools 
a = [functools.partial(lambda x: print(x), x) for x in range(10)] 

for i in a: 
    i()