【问题标题】:Python create function in a loop capturing the loop variablePython在循环中创建函数,捕获循环变量
【发布时间】:2009-07-10 01:01:25
【问题描述】:

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

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

funcs = []

for i in range(0,10):
    funcs.append(lambda x:f(i,x))

这不是我所期望的。我希望该列表的行为如下:

funcs[3](3) = 9
funcs[0](5) = 0

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

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

funcs[2](6) = 54

有什么想法吗?

【问题讨论】:

    标签: python lambda


    【解决方案1】:

    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))
    

    【讨论】:

    • 我同意。部分申请是这里的路。
    • 这里 partial(f,i) 代表 partial(f,b=i) 而不是 partial(f,a=i)。所以这和原来的帖子不一样。 '从右边'(gossamer-threads.com/lists/python/dev/715103)的部分功能申请已被拒绝两次。
    【解决方案2】:

    是的,通常的“范围界定问题”(实际上是一个比您想要的问题晚绑定的问题,但它通常被称为该名称)。你已经得到了两个最好的(因为最简单的)答案——“假默认”i=i 解决方案和functools.partial,所以我只给出经典三个中的第三个,“工厂 lambda”:

    for i in range(0,10):
        funcs.append((lambda i: lambda x: f(i, x))(i))
    

    我个人会选择i=i,如果funcs 中的函数没有被意外调用2 个参数而不是1 个的风险,但是当你需要更丰富的东西时,工厂函数方法值得考虑而不仅仅是预先绑定一个 arg。

    【讨论】:

    • 我没见过这个。有点整洁。
    • @ars,实际上对于大多数情况(在 Python 中)来说有点矫枉过正,但它是在(比如说)Scheme 中自然会做的事情,所以我猜它 有点整洁;-)。
    • 是的,我无法立即想到我更喜欢它的情况,但仍然是一个有趣的结构。 :-)
    【解决方案3】:

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

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

    for i in range(0,10):
        funcs.append(lambda x, i=i: f(i, x))
    

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

    【讨论】:

      【解决方案4】:

      所有的 lambdas 最终都绑定到最后一个。请参阅此问题以获得更长的答案:

      How do I create a list of Python lambdas (in a list comprehension/for loop)?

      【讨论】:

        【解决方案5】:

        考虑i == 9的最终值

        像任何好的 python 函数一样,它会在它定义的范围内使用变量的值。也许lambda: varname(因为它是一种语言结构)绑定到名称而不是值,并在运行时评估该名称?

        类似于:

        i = 9
        def foo():
            print i
        
        i = 10
        foo()
        

        我很想知道我的答案是否正确

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-11-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-09-16
          • 1970-01-01
          相关资源
          最近更新 更多