Python 中的 lambda 和作用域
给定这段代码:
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
值。