在Python中使用lambda表达式在循环中生成函数

31 投票
6 回答
9700 浏览
提问于 2025-04-15 16:39

如果我创建了两个函数列表:

def makeFun(i):
    return lambda: i

a = [makeFun(i) for i in range(10)]
b = [lambda: i for i in range(10)]

为什么列表 ab 的表现不一样呢?

举个例子:

>>> a[2]()
2
>>> b[2]()
9

6 个回答

7

一组函数(a)是对传入的参数进行操作,另一组函数(b)则是对一个全局变量进行操作,这个全局变量的值被设置为9。可以查看一下反汇编的结果:

>>> import dis
>>> dis.dis(a[2])
  1           0 LOAD_DEREF               0 (i)
              3 RETURN_VALUE
>>> dis.dis(b[2])
  1           0 LOAD_GLOBAL              0 (i)
              3 RETURN_VALUE
>>>
24

正如其他人提到的,问题出在作用域上。你可以通过给这个 lambda 表达式添加一个额外的参数,并为它设置一个默认值来解决这个问题:

>> def makeFun(i): return lambda: i
... 
>>> a = [makeFun(i) for i in range(10)]
>>> b = [lambda: i for i in range(10)]
>>> c = [lambda i=i: i for i in range(10)]  # <-- Observe the use of i=i
>>> a[2](), b[2](), c[2]()
(2, 9, 2)

这样一来,i 就被明确地限制在这个 lambda 表达式的作用域内了。

21

从技术上讲,lambda 表达式是对全局范围内可见的 i 进行了“闭合”,这个 i 最后被设置为 9。在这 10 个 lambda 表达式中,引用的都是同一个 i

i = 13
print b[3]()

makeFun 函数中,lambda 表达式闭合的是在函数被调用时定义的 i。这些是十个 不同i

撰写回答