在python中初始化lambda函数列表

在python中初始化lambda函数列表,python,python-3.x,lambda,closures,Python,Python 3.x,Lambda,Closures,我有一个元组的函数,我想预先加载一些数据。目前我这样做的方式如下。本质上,我列出了一个新函数的列表,并将lambda函数一次添加到其中,然后重新转换为元组。然而,当我在代码的不同部分使用这些函数时,它们中的每一个都会表现得好像它是列表中的最后一个一样 def newfuncs(data, funcs): newfuncs = [] for f in funcs: newf = lambda x: f(x, data) newfuncs.append

我有一个元组的函数,我想预先加载一些数据。目前我这样做的方式如下。本质上,我列出了一个新函数的列表,并将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打印两次。如果有人能帮助我理解为什么会发生这种情况,我将不胜感激。谢谢

这是一个众所周知的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
。这很酷,所以如果他们的回答对你有帮助,你应该接受。

这是一个众所周知的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
。这很酷,因此如果对您有帮助,他们的答案应该被接受。

如前所述,问题在于变量
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
s现在给出:

15
-5

如果您使用的是python3.x,请确保将其视为作用域默认arg方法的可能安全功能。

如前所述,问题在于变量
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
s现在给出:

15
-5

如果您使用的是python3.x,请确保将此作为作用域默认参数方法的一个可能的安全特性来考虑。

旁注:如果您使用的是python3,并且使用的是作用域默认参数方法,最好只使用关键字,因此,意外地传递额外的位置参数不会自动覆盖绑定值(您只能通过ex更改它们)