我在Python混合理解列表和lambdafunctions时不理解的行为

2024-05-19 03:20:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我不理解一个包含不同对象行为的lambda函数。它发生在一个大型项目中,所以对于这个问题,我制作了一个毫无意义的玩具箱来说明我的观点:

class Evaluator(object):
    def __init__(self, lft, rgt):
        self.lft = lft
        self.rgt = rgt

    def eval(self, x):
        return self.lft + x * (self.rgt - self.lft)


if __name__ == "__main__":
    ev1 = Evaluator(2, 3)
    ev2 = Evaluator(4, 5)
    ev3 = Evaluator(6, 7)
    funcs = [lambda x:ev.eval(x+0.1) for ev in (ev1, ev2, ev3)]
    print([f(0.5) for f in funcs])

我得到的输出是[6.6, 6.6, 6.6],这意味着它是ev3中一直被计算的方法。而不是[2.6, 4.6, 6.6],正如我所料。但真正让我吃惊的是,如果我去掉lambda函数,它的行为是好的:

^{pr2}$

返回[2.5, 4.5, 6.5]。有人能解释一下这是怎么回事吗?我应该如何用python的方式来编码呢?在


Tags: lambda函数inselfforevaluatordefeval
3条回答

问题是,您只在调用函数时计算ev。因此,它只在启动print语句时使用ev的任何值。当然,到那时,ev已经有了列表中最后一个函数的值。在

这和你这样做没有什么不同:

funcs = [lambda x: ev.eval(x+0.1),
         lambda x: ev.eval(x+0.1),
         lambda x: ev.eval(x+0.1)]

注意它们是如何使用ev,并且在您运行这些函数时,它们都将使用相同的相同的ev。在

要想做什么,您需要在定义理解时将ev绑定到列表理解中的当前值,您可以通过lambda参数传递值来实现:

^{pr2}$

但是,我强烈建议你这样做。正如您刚刚经历的,这样的代码很难理解和调试。在一行代码中尽可能多地使用功能是没有好处的。在

技术术语是闭包。有关详细信息,请查看stackoverflow上的以下问题: Why aren't python nested functions called closures?

问题在于lambdas的计算方式。这三只羔羊都是这样的:

ev.eval(x+0.1)

但是在理解之后,ev的值是ev3,因此这三个lambda都是相同的。在

可以通过在计算函数之前删除ev来观察这一点。您将得到一个属性错误。在

Why aren't python nested functions called closures?

{cddas>使用的lambdas来自于范围^ 1。执行lambda时,ev被绑定到ev3。在

注意:

a = 1

def x():
    print a

a = 2

x()   # prints 2

这里,ev是在lambda的创建时计算的:

^{pr2}$

相关问题 更多 >

    热门问题