2010-12-11 26 views
1

Python爲什麼在函數中改變不是全局聲明列表?爲什麼改變全球不會給錯誤?

RE更新的

numbers = [] 
num = 4 

def add(n, thisnum=None): 
    # changing global list without global declaration! 
    numbers.append(n) 
    if thisnum: 
     num = thisnum 
     print 'num assigned', thisnum 
    ##numbers = ('one', 'two', 'three') 
    ## adding this line makes error: 
"""Traceback (most recent call last): 
    File "J:\test\glob_vals.py", line 13, in <module> 
    add(i) 
    File "J:\test\glob_vals.py", line 6, in add 
    numbers.append(n) 
UnboundLocalError: local variable 'numbers' referenced before assignment 
""" 

for i in (1,2,3,564,234,23): 
    add(i) 

print numbers 
add(10, thisnum= 19) 
# no error 
print num 
# let the fun begin 
num = [4] 
add(10, num) 
print num 

# prints: 
"""[1, 2, 3, 56, 234, 23] 
num assigned 19 
4 
num assigned [4] 
[4] 

""" 

如果我把assignement變量同名那麼行動該行之前成爲錯誤,而不是添加的行(字節碼編譯點吧,我猜)。

+0

您似乎對範圍規則感到困惑。有一些關於這個問題的質量問題遍佈於SO,docs.python.org也涵蓋了這一點。 – delnan 2010-12-11 17:18:30

+0

我仍然認爲這不是微不足道的事情,或者從我已經學習很多的文檔中看得很清楚,自1984年以來一直擔任老師和學習計算機科學。 – 2010-12-11 17:33:26

+0

我認爲這很簡單 - 或許比大多數語言的範圍規則更復雜,但仍然只有一個少數規則沒有討厭的例外。 – delnan 2010-12-11 17:55:18

回答

5

您不是分配給全局變量,而是調用其中更改其內容的方法。這是允許的。

什麼,你不能沒有global關鍵字做的是:

def add(n): 
    #global numbers 
    numbers = numbers + [n] 

結果:

 
Traceback (most recent call last): 
    File "C:\Users\Mark\Desktop\stackoverflow\python\test.py", line 8, in 
    add(i) 
    File "C:\Users\Mark\Desktop\stackoverflow\python\test.py", line 5, in add 
    numbers = numbers + [n] 
UnboundLocalError: local variable 'numbers' referenced before assignment 

不同的是,我在這裏沒有變異現有列表 - 我想創建一個新列表並重新分配到全球範圍。但是,如果沒有global關鍵字,這是無法完成的。


關於你提到的更新:

下面一行是可以的,因爲它的功能範圍創建一個新的本地名稱num。這不會影響全局範圍內變量的值。

num = thisnum 
0

因爲你只是附加到列表中。

訪問和分配是不同的概念。當你附加一個列表時,你只是調用一個方法來改變它的值。假設你做了+=,那就是分配。

如果你做到這一點:

>>> numbers = [] 
>>> def add(n): 
     numbers += n 

>>> n = [1, 2] 
>>> add(n) 

這將失敗,因爲這是任務。

要解決這個問題,在add()功能,您可以添加:

>>> def add(n): 
     global numbers 
     numbers += n 
1

global x只有 affests x = ...(即,它使這種重新分配全球x,而不是創建一個獨立的本地x)。它不會影響x.member = ...(因爲這是一個方法調用)或x.mutating_method(...),因爲Python(這個不是靜態與動態的問題,順便說一句)不知道(也不在乎)這些方法修改self以某種方式 - 所以你必須防止方法調用(指向對象)全局變量......這當然是毫無意義的。

關於更新: 當你做num = thisnum,你正在做的事情完全不同於numbers.append(n) - 要創建一個局部變量(因爲你沒有申報global num),並賦予其一定的價值。這從來沒有觸及全球num

+0

請參閱重新更新,現在它確實觸及它。 – 2010-12-11 17:47:26

+0

@Tony:看到我的第一句話--Python假設'x'是本地的,如果它被分配給函數中的某個地方,並且由於錯誤信息告訴你,本地'numbers'(它是本地的,因爲它*稍後被分配)在函數中並且沒有聲明爲'global')在那時沒有賦值給它。 – delnan 2010-12-11 17:54:21

+0

我明白了,但是由於後面的一行,它會讓'回到未來'的效果變得更好,導致之前沒有出現錯誤的行。它只是強調字節編譯步驟的存在。並且將其作爲變量傳遞給列表,而不是將其寫入與直接參數相同的值,從而將副作用返回給調用者。 – 2010-12-11 18:36:10