Python 中的 lambda 和作用域

8 投票
3 回答
621 浏览
提问于 2025-04-15 17:08

给定这段代码:

funcs = []
for x in range(3):
    funcs.append(lambda: x)
print [f() for f in funcs]

我本以为它会打印出 [0, 1, 2],但实际上它打印的是 [2, 2, 2]。我是不是对lambda表达式和作用域的理解有什么根本性的错误?

3 个回答

4

你知道答案的:是的。 ;) 不过别担心,这对刚开始学习Python的人来说是很常见的发现。当你定义一个函数或者用lambda表达式时,如果里面引用了在这个函数外部定义的变量,就会产生一个闭包。这个闭包的效果是,当你调用这个函数时,得到的是调用时变量的值,而不是定义时的值。(你可能期待的是后者。)

处理这个问题有几种方法。第一种是绑定额外的变量:

funcs = []
for x in range(10):
    funcs.append(lambda x=x: x)
print [f() for f in funcs]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

第二种方法稍微正式一点:

from functools import partial
funcs = []
for x in range(10):
    funcs.append(partial(lambda x: x, x))
print [f() for f in funcs]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
5

x 绑定到了模块级别的 x(这个是从 for 循环中留下来的)。

再简单一点:

funcs = []

for x in range(10):
    funcs.append(lambda: x)

x = 'Foo'

print [f() for f in funcs]

# Prints ['Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo']
9

这是一个在Python中常见的问题。简单来说,作用域的规则是,当你调用f()时,它会使用当前的x值,而不是在创建lambda表达式时的x值。为了避免这个问题,有一个标准的解决办法:

funcs = []
for x in range(10):
funcs.append(lambda x=x: x)
print [f() for f in funcs]

使用lambda x = x可以获取并保存当前的x值。

撰写回答