2012-07-06 86 views
3

今天我探索的Python 怪异行为。举个例子:如何强制Python在循环内创建新变量/新范围?

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()) 

上面的代码打印

3 
3 
3 

但我想它打印

1 
2 
3 

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

+0

提示:在Python中引入了一个新的变量作用域? – 2012-07-06 16:49:13

+0

刚刚看到http://stackoverflow.com/questions/7546285/creating-lambda-inside-a-loop?rq=1是一个重复的问题。我怎样才能关闭这个或我应该删除它? – 2012-07-06 16:49:38

+0

@tampis:只需投票结束 - 版主将最终决定是否合并或删除此问题。 – 2012-07-06 16:51:38

回答

8

要做到这一点,最简单的方法是使用默认参数为您的拉姆达,这样的x当前值绑定的的var功能的默认参数,而不是抬头中含有范围在每次调用:

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

for c in closures: 
    print(c()) 

或者,你可以创建一个闭包(你有什么是不封闭的,因为在全球被创建的每个功能SCOP E):

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()也可以写成这样,这可能使其更易于阅读:

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

+1对于很好的解释 – 2012-07-06 16:53:47

6

不能创建在循环内的局部范围内的新变量。无论您选择何种名称,您的功能将始终是该名称的封闭并使用其最新值。

解决这个问题的最简单的方法是使用关键字参数:

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

感谢您的编辑,现在可以+1。 – 2012-07-06 16:56:49

1

在你的榜样,var总是绑定到循环的最后一个值。您需要使用closures.append(lambda var=var: var)将其绑定在lambda表达式中。