这个python函数中的lambda表达式发生了什么?

时间:2009-05-08 20:03:44

标签: python lambda

为什么尝试创建curried函数列表不起作用?

def p(x, num):
    print x, num

def test():
    a = []
    for i in range(10):
        a.append(lambda x: p (i, x))
    return a

>>> myList = test()
>>> test[0]('test')
9 test
>>> test[5]('test')
9 test
>>> test[9]('test')
9 test

这里发生了什么?

实际执行我期望上述功能的功能是:

import functools
def test2():
    a = []
    for i in range (10):
        a.append(functools.partial(p, i))
    return a


>>> a[0]('test')
0 test
>>> a[5]('test')
5 test
>>> a[9]('test')
9 test

4 个答案:

答案 0 :(得分:12)

在Python中,在循环和分支中创建的变量不是作用域。您使用lambda创建的所有函数都引用了相同的i变量,该变量在循环的最后一次迭代时设置为9

解决方案是创建一个返回函数的函数,从而确定迭代器变量的范围。这就是functools.partial()方法有效的原因。例如:

def test():
    def makefunc(i):
        return lambda x: p(i, x)
    a = []
    for i in range(10):
        a.append(makefunc(i))
    return a

答案 1 :(得分:1)

那么你也可以将i绑定到懒惰的外部lambda。

def p(x, num):
    print x, num

def test():
    a = []
    for i in range(10):
        a.append((lambda i :lambda x: p (i, x))(i))
    return a

答案 2 :(得分:1)

我一直很困惑为什么这不起作用。感谢您的解释,'a paid nerd'。我个人更喜欢这个解决方案:

for i in range(10):
    a.append(lambda num, val_i=i: p (val_i, num))

注意val_i=i的{​​{1}}默认参数,它允许在循环期间捕获lambda的瞬时值,同时仍然有效地使i成为1变量的函数。 (顺便说一句:将lambda更改为x以匹配num的定义。)我更喜欢它,因为:

  1. 它非常接近原始的想法,避免了必须定义一个新的命名函数,正是lambda的目的......
  2. 避免导入p
  3. 并避免瓦解羊羔......
  4. 刚刚进行了搜索并找到了有关同一问题的更详细解释:Scope of python lambda functions and their parameters

答案 3 :(得分:0)

我问了一个类似的问题,得到了两个答案。一个与这里接受的答案基本相同,另一个不太清楚,但稍微更加苛刻。

Dynamically creating a menu in Tkinter. (lambda expressions?)