Python:List Comprehensions中的Lambda函数
为什么以下两个列表parsing的输出不同,即使f和lambda函数是相同的?
f = lambda x: x*x [f(x) for x in range(10)]
和
[lambda x: x*x for x in range(10)]
请注意,types(f)和types(lambda x:x * x)都返回相同的types。
第一个创build一个lambda函数并调用它十次。
第二个不叫这个函数。 它创build10个不同的lambda函数。 它把所有这些放在一个列表中。 为了使它相当于你需要的第一个:
[(lambda x: x*x)(x) for x in range(10)]
或者更好的是:
[x*x for x in range(10)]
这个问题触及了“着名”和“显而易见的”Python语法的一个非常糟糕的部分 – 优先,lambda或for列表理解。
我不认为OP的目的是生成一个从0到9的方块列表。如果是这样的话,我们可以给出更多的解决scheme:
squares = [] for x in range(10): squares.append(x*x)
- 这是命令式语法的好方法。
但这不是重点。 问题是W(hy)TF是这个模棱两可的expression,所以反直觉? 最后,我还有一个愚蠢的例子,所以不要太早拒绝我的回答(我在面试时曾经这样做过)。
所以,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的内存地址 – 它们都是不同的!
你当然可以有一个更“优化”(哈哈)版本的这个expression式:
>>> [lambda x: x*x] * 3 [<function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>, <function <lambda> at 0x00000000023AD2E8>]
看到? 3次相同的 lambda。
请注意,我用_
作为variables。 它与lambda
的x
没有任何关系(它是词法上的阴影!)。 得到它?
我正在讨论这个问题,为什么语法的优先顺序不是这样,这一切意味着:
[lambda x: (x*x for x in range(10))]
这可能是[[0, 1, 4, ..., 81]]
或[(0, 1, 4, ..., 81)]
,或者我认为最合理的 ,这将是1个元素 – 一个generator
返回值。 事实并非如此,语言不是这样工作的。
但是什么,如果…
如果你没有掩盖for
variables,并在你的lambda
s中使用它?
那么,垃圾发生。 看这个:
[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)]
这太疯狂了!
列表理解中的lambdas是关于这个理解范围的封闭。 一个词汇封闭,所以他们指的是i
通过参考,而不是它的价值,当他们被评估!
所以,这个expression式:
[(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-agnostic的讨论,这已经足够了。 面试的问题非常多。
现在,如何制作一个乘法器lambdas list
,真正乘以连续的整数? 那么,与被接受的答案类似,我们需要通过将它包装到另一个lambda
,这个lambda
在列表理解expression式中被调用,
之前:
>>> 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
(我的外层lambdavariables也是= i
,但我决定这是更清晰的解决scheme – 我介绍了y
以便我们都可以看到哪个女巫是哪个)。
最大的区别是第一个例子实际上调用lambda f(x)
,而第二个例子不是。
你的第一个例子相当于[(lambda x: x*x)(x) for x in range(10)]
而第二个例子相当于[f for x in range(10)]
。
第一个
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,以便生成所有这些函数。
人们给出了很好的答案,但忘了提到我认为最重要的部分:在第二个例子中,列表理解的X
与lambda
函数的X
不是一样的,它们是完全不相关的。 所以第二个例子实际上是一样的:
[Lambda X: X*X for I in range(10)]
range(10)
的内部迭代只负责在列表中创build10个类似的lambda函数(10个独立的函数,但完全相似 – 返回每个input的功率2)。
另一方面,第一个例子完全不同,因为迭代X与结果交互,对于每次迭代,值是X*X
所以结果是[0,1,4,9,16,25, 36, 49, 64 ,81]
其他的答案是正确的,但是如果你正在尝试做一个函数列表,每个函数都有一个不同的参数,那么以后可以执行下面的代码:
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()