2016-02-28 46 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