lambda函数如何在python中引用它的参数?

dol*_*eng 6 python lambda closures functional-programming

我是Python新手.我的任务很简单 - 我需要一个可以用来批量处理的函数列表.所以我玩了一些例子

fs = [lambda x: x + i for i in xrange(10)]
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,电话

[f(0) for f in fs]
Run Code Online (Sandbox Code Playgroud)

给了我一些结果[9, 9, 9, 9, 9, 9, 9, 9, 9, 9].这不是我的预期,因为我希望变量i在不同的函数中具有不同的值.

所以我的问题是:

  1. ilambda中的变量是全局变量还是本地变量?

  2. python与javascript中的'closure'有相同的概念吗?我的意思是这里的每个lambda都包含对i变量的引用,或者它们只保存i每个中的值的副本?

  3. 如果我想[0, 1, .....9]在这种情况下输出,我该怎么办?

Gre*_*ill 10

它看起来有点乱,但你可以通过做这样的事情得到你想要的东西:

>>> 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]
Run Code Online (Sandbox Code Playgroud)

通常,Python支持"闭包"概念,类似于您在Javascript中习惯使用的概念.但是,对于列表解析中lambda表达式的这种特殊情况,似乎i只绑定一次并连续接受每个值,使每个返回的函数表现得就好像i是9.上面的hack明确地传递了每个值i使用捕获的值,返回另一个lambda的lambda y.


nco*_*lan 6

您遇到的问题是"早期绑定"和"后期绑定"之间的区别.

当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]
Run Code Online (Sandbox Code Playgroud)

两种方法都有效.Greg的优点是不会弄乱返回的函数的签名,默认参数hack比定义命名函数而不是使用lambda表达式时添加额外的闭包级别更快且更具可读性.