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返回值。 事实并非如此,语言不是这样工作的。 
但是什么,如果…
 如果你没有掩盖forvariables,并在你的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()