在python中初始化lambda函数列表

时间:2017-10-03 00:32:37

标签: python python-3.x lambda closures

我有一些函数元组,我想用一些数据预先加载。目前,我这样做的方式如下。本质上,我列出了新函数,并一次一个地添加lambda函数,然后重新转换为元组。但是,当我在代码的不同部分使用这些函数时,每个函数都表现为列表中的最后一个函数。

def newfuncs(data, funcs):
    newfuncs = []
    for f in funcs:
        newf = lambda x: f(x, data)
        newfuncs.append(newf)
    return tuple(newfuncs)

以下是问题的一个简单示例

funcs = (lambda x, y: x + y, lambda a, b: a - b)
funcs = newfuncs(10, funcs)
print(funcs[0](5))
print(funcs[1](5))

我希望打印数字15,然后是-5。但是,此代码打印数字-5两次。如果有人能帮助我理解为什么会这样,那将非常感激。谢谢!

2 个答案:

答案 0 :(得分:3)

如上所述,问题在于变量f,它是分配给所有 lambda函数的变量,因此在循环结束时,每个 lambda都会看到相同的f

此处的解决方案是使用functools.partial,或为lambda创建作用域默认参数:

def newfuncs(data, funcs):
    newfuncs = []
    for f in funcs:
        newf = lambda x, f=f: f(x, data)   # note the f=f bit here
        newfuncs.append(newf)
    return tuple(newfuncs) 

现在像以前一样调用这些lambda给出:

15
-5

如果您正在使用python3.x,请务必查看此comment by ShadowRanger作为作用域默认arg方法的可能安全功能。

答案 1 :(得分:2)

这是一个众所周知的Python“问题”,或者我应该说“这只是Python的方式。”

您创建了元组:

( x => f(x, data), x => f(x, data) )

但是f是什么?在最终调用函数之前,不会对f进行求值!

首先,f(x, y)=>x+y。然后在for循环中, f被重新分配到 (x, y)=>x-y

当你最终调用你的函数时,那么,只有这样,才会查找f的值。此时f的价值是多少?所有功能的值均为(x, y)=>x-y 。你的所有函数都做减法。这是因为f被重新分配。只有一个f。并且在调用任何lambda之前,将该值和f的值设置为减法函数。

<强>附录

如果有人感兴趣,不同的语言会以不同的方式解决这个问题。 JavaScript在这里相当有趣(有些人会说是混乱),因为它以Python的方式执行,OP发现意外,以及OP预期的不同方式。在JavaScript中:

> let funcs = []
> for (let f of [(x,y)=>x+y, (x,y)=>x-y]) {
    funcs.push(x=>f(x,10));
  }
> funcs[0](5)
15
funcs[1](5)
-5

但是,如果您将let更改为上面的var,它的行为就像Python一样,两者都得到-5!这是因为使用let,for循环的每次迭代都会得到不同的f;使用var,整个函数共享相同的f,这将继续重新分配。这就是Python的工作原理。

cᴏʟᴅsᴘᴇᴇᴅ向你展示了你所期望的方法是确保你为每次迭代得到不同的f,Python允许你以一种非常简洁的方式做到,默认lambda的第二个参数到该迭代的本地f。这很酷,所以如果对你有帮助,他们的答案应该被接受。