如何强制Python在循环中创建新的变量/新范围?

How can I force Python to create a new variable / new scope inside a loop?

本问题已经有最佳答案,请猛点这里访问。

今天我研究了Python的一种奇怪行为。一个例子:

1
2
3
4
5
6
7
8
9
10
closures = []
for x in [1, 2, 3]:
    # store `x' in a"new" local variable
    var = x

    # store a closure which returns the value of `var'
    closures.append(lambda: var)

for c in closures:
    print(c())

以上代码打印

1
2
3
3
3
3

但我想把它打印出来

1
2
3
1
2
3

我为自己解释了这种行为,即var始终是相同的局部变量(而python并不像其他语言那样创建新的局部变量)。如何修复上述代码,以便每个闭包返回另一个值?


最简单的方法是为lambda使用默认参数,这样,EDOCX1的当前值(0)就被绑定为函数的默认参数,而不是在每次调用的包含范围中查找var

1
2
3
4
5
6
closures = []
for x in [1, 2, 3]:
    closures.append(lambda var=x: var)

for c in closures:
    print(c())

或者,您可以创建一个闭包(您拥有的不是闭包,因为每个函数都是在全局范围内创建的):

1
2
3
4
5
6
7
make_closure = lambda var: lambda: var
closures = []
for x in [1, 2, 3]:
    closures.append(make_closure(x))

for c in closures:
    print(c())

make_closure()也可以这样写,这样可以使它更易读:

1
2
def make_closure(var):
    return lambda: var


不能在循环内的本地作用域中创建新变量。无论您选择什么名称,您的函数都将始终是该名称的闭包,并使用其最新值。

最简单的方法是使用关键字参数:

1
2
3
closures = []
for x in [1, 2, 3]:
    closures.append(lambda var=x: var)


在您的示例中,var始终绑定到循环的最后一个值。您需要使用closures.append(lambda var=var: var)将它绑定到lambda中。