2016-02-28 49 views
0

我有局部变量的测试巢功能, 我得到了错误如下面的代码:巢功能Python的本地名称

# coding: utf-8 

def func3(): 
    x = [1, 2, 3] 

    def func2(): 
     print 'func2:', locals() 
     x[0] += x[0] 
     print 'func2:', locals() 

    def func3(): 
     print 'func3:', locals() 
     x = x[0] 
     print 'func3:', locals() 

    func2() 
    print "-->", locals() 

    func3() 
    print "==>", locals() 

if __name__ == '__main__': 
    func3() 

我得到了错误:

func2: {'x': [1, 2, 3]} 

func2: {'x': [2, 2, 3]} 

--> {'func3': <function func3 at 0x1076adde8>, 'func2': <function func2 at 0x1076ad6e0>, 'x': [2, 2, 3]} 

func3: {} 

Traceback (most recent call last): 

    File "test.py", line 23, in <module> 

    func3() 

    File "test.py", line 19, in func3 

    func3() 
    File "test.py", line 13, in func3 

    x = x[0] 

UnboundLocalError: local variable 'x' referenced before assignment 

为什么func2func3有不同的答案吗?

回答

2

如果函数中存在对某个变量的赋值,则会在该函数中创建一个局部变量,并且假定所有对同名的引用都是该局部变量的引用。否则,假定对变量的引用会转到外部作用域。

func2没有转让给x(有一个任务x[0],但这不是一回事)。因此它指的是外部x,并且一切正常。

但是,在func3有一个x的任务。因此该函数中的x引用了该函数本地的一个新变量,而x = x[0]是错误的,因为它试图读取未初始化的变量。

在Python 3中,您可以将nonlocal x设置为func3,而不是分配给外部x。在Python 2中,没有简单的方法从外部非全局范围分配给变量。通常的解决方法是使用索引,如func2或写入属性(x.attr = val)。

0

func3()中,您试图修改外部范围中的变量。然而,你并没有说它不是本地的,所以Python说本地变量在赋值之前被引用。要修改外部变量,需要声明其非本地(以Python3):

def func3(): 
    nonlocal x 
    print 'func3:', locals() 
    x = x[0] 
    print 'func3:', locals() 

这不会在Python2不过工作,因为nonlocal不存在。一种解决方法是在外部func3()和内部func3()中声明x全局。

func2()的情况下,您并不需要这样做,因为x[0] += x[0]实际上是x[0].__iadd__(x[0])的快捷方式。既然你被允许参考x,这就是你想要的。

+0

'x'不是全局的,它来自外部范围。 'func2'是正确的,没有任何额外的'global'或'nonlocal'声明。 – interjay

+0

@interjay我已经编辑了我的答案,但你来得太早了27秒。看看我对'global''和'nonlocal'的回归的其他答案的评论。 – zondo

+0

答案仍然错误。 'func2'不会访问外部变量。 – interjay