lambda函数在python中如何引用其参数?
我是Python新手。我的任务很简单——我需要一个函数列表,可以用它成批完成任务。所以我用了一些例子,比如lambda函数在python中如何引用其参数?,python,lambda,functional-programming,closures,Python,Lambda,Functional Programming,Closures,我是Python新手。我的任务很简单——我需要一个函数列表,可以用它成批完成任务。所以我用了一些例子,比如 fs = [lambda x: x + i for i in xrange(10)] 令人惊讶的是 [f(0) for f in fs] 给我的结果是[9,9,9,9,9,9,9,9,9]。这不是我所期望的,因为我希望变量I在不同的函数中具有不同的值 所以我的问题是: lambda中的变量i是全局变量还是局部变量 python的概念是否与javascript中的“闭包”相同?我的意思是
fs = [lambda x: x + i for i in xrange(10)]
令人惊讶的是
[f(0) for f in fs]
给我的结果是[9,9,9,9,9,9,9,9,9]
。这不是我所期望的,因为我希望变量I
在不同的函数中具有不同的值
所以我的问题是:
i
是全局变量还是局部变量I
变量的引用,或者它们只是在每个lambda中持有I
值的副本[0,1,…9]
,该怎么办看起来有点凌乱,但你可以通过这样做得到你想要的:
>>> fs = [(lambda y: lambda x: x + y)(i) for i in xrange(10)]
>>> [f(0) for f in fs]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
通常Python支持“闭包”概念,类似于Javascript中的闭包概念。然而,对于列表理解中lambda表达式的这种特殊情况,似乎i
只绑定了一次,并连续接受每个值,使每个返回函数的作用就像i
是9一样。上面的hack显式地将i
的每个值传递到lambda,该lambda使用捕获的y
值返回另一个lambda
i
是列表理解的局部变量,但它对lambda可用,因为lambda在其范围内xrange(10)
上循环。你可以用lambdas来做这件事(见另一个答案),但你不想这样做。Lambdas应该非常谨慎地使用lambda以这种方式运行的原因是,对于每个循环,
i
都是反弹。因为我不是lambda的本地值,所以它也会发生变化,最后一个值是9。所以你所做的就是0+9
10次。i是本地的,python中确实有闭包
我相信您的困惑在于您将fs分配给一个相同函数的列表
>>> fs = [lambda x: x + i for i in xrange(10)]
>>> fs
[<function <lambda> at 0x02C6E930>, <function <lambda> at 0x02C6E970>, <function <lambda> at 0x02C6E9B0>, <function <lambda> at 0x02C6E9F0>, <function <lambda> at 0x02C6EA30>, <function <lambda> at 0x02C6EA70>, <function <lambda> at 0x02C6EAB0>, <function <lambda> at 0x02C6EAF0>, <function <lambda> at 0x02C6EB30>, <function <lambda> at 0x02C6EB70>]
>>> fs[0](0)
9
>>> fs[0](100)
109
>>> fs[5](0)
9
>>> fs[5](100)
109
fs=[λx:x+i表示x范围内的i(10)]
>>>财政司司长
[, , , , , ]
>>>fs[0](0)
9
>>>fs[0](100)
109
>>>fs[5](0)
9
>>>fs[5](100)
109
我认为单个函数返回一个列表会更合适
>>> fs3 = lambda x: [x + i for i in xrange(10)]
>>> fs3
<function <lambda> at 0x02C6EC70>
>>> fs3(0)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
fs3=lambda x:[x+i代表x范围内的i(10)]
>>>fs3
>>>fs3(0)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
这里遇到的问题是“早期绑定”和“后期绑定”之间的区别 当Python从外部范围(在本例中为
i
)查找变量时,它使用后期绑定。这意味着它在调用函数时看到该变量的值,而不是在定义函数时看到的值
因此,在您的示例代码中,所有10个lambda函数都会看到循环过程分配给i
变量的最终值:9
Greg的回答显示了一种强制早期绑定行为的方法(即创建一个额外的闭包,并在循环中立即调用它)
强制早期绑定语义的另一种常用方法是“默认参数hack”,它在函数定义时将变量绑定为默认参数:
>>> fs = [(lambda x, _i=i: x + _i) for i in xrange(10)]
>>> [f(0) for f in fs]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
这两种方法都有效。Greg的优点是不干扰返回函数的签名,默认参数破解比定义命名函数而不是使用lambda表达式时添加额外的闭包级别更快,可读性更高。是的,上面的技巧很聪明。它通过使用一个额外的闭包来创建本地副本。实际上,闭包的工作方式与预期的一样(捕获变量,而不是在闭包创建时捕获变量的值),JS也这样做(尝试在循环中创建函数)。似乎我只绑定了一次,并连续接受每个值。。。如果是这样的话,
i
的值不应该是0
,因为它是由xrange
生成的第一个值吗?是的,很高兴知道python中有另一种黑客攻击。格雷格的技巧在Javascript中有对应关系,但你的技巧对我来说是新的。谢谢你的解释