Python Lambda问题

Dan*_*enc 15 python lambda

这里发生了什么?我正在尝试创建一个函数列表:

def f(a,b):
    return a*b

funcs = []

for i in range(0,10):
    funcs.append(lambda x:f(i,x))
Run Code Online (Sandbox Code Playgroud)

这不符合我的期望.我希望列表的行为如下:

funcs[3](3) = 9
funcs[0](5) = 0
Run Code Online (Sandbox Code Playgroud)

但是列表中的所有函数似乎都是相同的,并且将固定值设置为9:

funcs[3](3) = 27
funcs[3](1) = 9

funcs[2](6) = 54
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Rya*_*yan 19

python中的lambdas是闭包....你给它的参数在评估lambda之前不会被评估.那时候i = 9,因为你的迭代完成了.

您正在寻找的行为可以通过functools.partial实现

import functools

def f(a,b):
    return a*b

funcs = []

for i in range(0,10):
    funcs.append(functools.partial(f,i))
Run Code Online (Sandbox Code Playgroud)


Ale*_*lli 13

是的,通常的"范围问题"(实际上是一个绑定 - 后来比你想要的问题,但它经常被这个名称调用).你已经得到了两个最好的(因为最简单的)答案 - "假默认" i=i解决方案functools.partial,所以我只给出经典三个中的第三个,即"工厂lambda":

for i in range(0,10):
    funcs.append((lambda i: lambda x: f(i, x))(i))
Run Code Online (Sandbox Code Playgroud)

就个人而言,i=i如果不存在funcs使用2个参数而不是1个意外调用函数的风险,我会选择,但是当你需要比预绑定一个arg更丰富的东西时,工厂函数方法是值得考虑的.

  • 我以前没见过这个.有点整洁. (2认同)

ars*_*ars 11

只有一个i绑定到每个lambda,与你的想法相反.这是一个常见的错误.

获得你想要的东西的一种方法是:

for i in range(0,10):
    funcs.append(lambda x, i=i: f(i, x))
Run Code Online (Sandbox Code Playgroud)

现在,您将i在每个lambda闭包中创建一个默认参数,并将循环变量的当前绑定到该闭包i.