为什么以下两个列表推导的输出不同,即使f和lambda函数相同?
f = lambda x: x*x
[f(x) for x in range(10)]
和
[lambda x: x*x for x in range(10)]
请注意,类型(f)和类型(lambda x:x * x)都返回相同的类型。
答案 0 :(得分:194)
第一个创建一个lambda函数并调用它十次。
第二个不调用该函数。它创建了10种不同的lambda函数。它将所有这些放在一个列表中。使它等同于你需要的第一个:
[(lambda x: x*x)(x) for x in range(10)]
或者更好:
[x*x for x in range(10)]
答案 1 :(得分:69)
这个问题涉及“着名的”和“明显的”Python语法的一个非常臭的部分 - 优先级,lambda或列表理解的for。
我不认为OP的目的是生成从0到9的正方形列表。如果是这样的话,我们可以提供更多的解决方案:
squares = []
for x in range(10): squares.append(x*x)
但这不是重点。重点是W(hy)TF是这个模糊的表达所以反直觉吗?最后我有一个愚蠢的案例,所以不要过早地解答我的答案(我在面试时就已经过了)。
所以,OP的理解返回了一个lambdas列表:
[(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的内存地址 - 它们都不同!
你当然可以拥有这个表达式的更“最佳”(haha)版本:
>>> [lambda x: x*x] * 3
[<function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>]
请参阅? 3次相同的 lambda。
请注意,我使用_
作为for
变量。它与x
中的lambda
无关(它在词汇上黯然失色!)。得到它?
我要省略讨论,为什么语法优先权不是这样,这一切都意味着:
[lambda x: (x*x for x in range(10))]
可以是:[[0, 1, 4, ..., 81]]
,或[(0, 1, 4, ..., 81)]
,或我认为最符合逻辑的,这将是{1}}的1个元素 - 一个{{ 1}}返回值。事实并非如此,语言不会这样。
但是什么,如果......
如果你没有掩盖list
变量,并在你的generator
中使用它,该怎么办?
for
这当然意味着:
lambda
但这并不意味着:
[lambda x: x * i for i in range(4)]
这太疯狂了!
列表理解中的lambdas是对这种理解范围的封闭。一个词汇闭包,所以它们引用[(lambda x: x * i) for i in range(4)]
via引用,而不是它们在评估时的值!
所以,这个表达式:
[(lambda x: x * 0), (lambda x: x * 1), ... (lambda x: x * 3)]
大致等同于:
i
我确信我们可以在这里看到更多使用python反编译器(我的意思是例如[(lambda x: x * i) for i in range(4)]
模块),但对于Python-VM不可知的讨论,这就足够了。
求职面试的问题非常多。
现在,如何制作一个[(lambda x: x * 3), (lambda x: x * 3), ... (lambda x: x * 3)]
乘数lambdas,它真正乘以连续的整数?好吧,与接受的答案类似,我们需要通过将其包含在另一个dis
中来打破与list
的直接联系,这将被称为 in 列表推导表达式:< / p>
在:
i
后:
lambda
(我的外部lambda变量也是>>> 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
以便我们都可以看到哪个女巫是哪个。
答案 2 :(得分:17)
最大的区别是第一个例子实际上调用了lambda f(x)
,而第二个例子却没有。{/ p>
您的第一个示例相当于[(lambda x: x*x)(x) for x in range(10)]
,而您的第二个示例相当于[f for x in range(10)]
。
答案 3 :(得分: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)]
为列表中的每个值运行lambda,因此它会生成所有这些函数。
答案 4 :(得分:4)
人们给出了很好的答案,但忘记提及我认为最重要的部分:
在第二个示例中,列表推导的X
与X
函数的lambda
不同,它们完全不相关。
所以第二个例子实际上与:
[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]
答案 5 :(得分: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()