2013-09-28 18 views
0
def counter(x): 

    def _cnt(): 
     #nonlocal x 
     x = x+1 
     print(x) 
     return x 

    return _cnt 
a = counter(0) 
print(a()) 

上面的代码提供了以下错误Python的闭包

UnboundLocalError:局部变量“X”分配

这是为什么没能在创造与价值“X + 1”的新对象之前引用_cnt的命名空间并将其绑定到x。我们将在两个函数名称空间中都有引用x

回答

2

只要您在给定作用域中分配给某个名称,那么在同一作用域内对同一名称的所有引用都是本地作用域。因此x + 1无法评估(因为它试图引用本地x)。

因此这个工程:

def f(): 
    x = 42 
    def g(): 
     print(x) 
    g() 
f() 

但这并不:

def f(): 
    x = 42 
    def g(): 
     print(x) 
     x = 42 
    g() 
f() 

第一print有这样的字节码:

0 LOAD_GLOBAL    0 (print) 
3 LOAD_DEREF    0 (x) 
6 CALL_FUNCTION   1 
9 POP_TOP 

而第二print具有这样一个:

0 LOAD_GLOBAL    0 (print) 
3 LOAD_FAST    0 (x) 
6 CALL_FUNCTION   1 
9 POP_TOP 
+0

我认为像'x = x + 1'这样的赋值语句是这样执行的。评估第一个表达式x + 1(所以x指的是计数器的x),然后将表达式的返回值赋给x(这应该在_cnt的命名空间中创建一个新的引用 – user634615

+0

正如您在第二个示例中所见,尽快因为你分配了一个名字,所有对它的引用都变成本地的,不管它们是在赋值之前还是之后发生的。 – Hyperboreus

+0

@ user634615我加了反汇编,'LOAD_FAST'是失败的。 – Hyperboreus

0

的功能counter的范围和_cnt是不一样的。即使它们嵌套,也没关系。

所以xcounter不存在于_cnt。也许将它作为参数传递(或者使用nonlocal,因为你似乎已经理解了)