2012-08-28 54 views
0

我有一個關於Python中的局部和全局變量和全局對象的問題。看看這段代碼:本地,全局和Python中的對象

var = 0 

class Test(): 
    var = 0 

test = Test() 

def sum(): 
    Test.var += 1 
    test.var += 1 
    var += 1 

sum() 

如果我運行該代碼,只會在「var + = 1」行中觸發異常。前兩行工作。我從Python常見問題中讀取this question。我認爲在函數的前兩行中沒有例外,因爲引用了「測試」和「測試」。成員「var」被賦值,但「Test」和「test」是全局的,因爲被引用來獲取成員。常見問題解答說:「在Python中,只能在函數內引用的變量隱式地是全局變量,如果變量在函數體內的任何位置被分配了一個新值,則它被假定爲本地變量。」

所以,問題是......我的假設是真的嗎?

回答

1

我認爲有在 功能的前兩行也不例外,因爲「測試」和「測試」被引用。

正確。它們引用類屬性var,而不是您定義的全局屬性。

成員「VAR」分配,但由於被引用,以獲得會員「測試」和「測試」是全球性的。

,或者換一種說法,Testtest在全局命名空間,這樣Test.vartest.var工作可用。

如果var的值在sum()中未更改,您將得到0,因爲它上面的行已更改Test類屬性而非全局值。在添加一些和print S和去除var += 1

def sum(): 
    Test.var += 1 
    print Test.var 
    test.var += 1 
    print test.var 
    print var 

sum() 

...給:

1 
2 
0 

但當下我嘗試SUM函數內的值賦給VAR,我甚至得到一個錯誤

>>> def sum(): 
...  Test.var += 1 
...  print Test.var 
...  test.var += 1 
...  print test.var 
...  print var 
...  var += 1 
...  print var 
... 
>>> sum() 
1 
2 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 6, in sum 
UnboundLocalError: local variable 'var' referenced before assignment 

因爲var現在正在總和()指定一個值,它被認爲是本地,但尚未在此之前,升定義:該行之前國家統計局。 (這意味着Python是做一些「向前看」或總和檢查variable scope(),因爲它提高了第一print var錯誤var之前重新assinged。把var = 50代替var += 1引發同樣的錯誤。)

要使用全局變量工作:

def sum(): 
    Test.var += 1 
    print Test.var 
    test.var += 1 
    print test.var 
    global var #added the global keyword 
    print var 
    var += 1 
    print var 

輸出:

1 
2 
0 # notice that global var is still 0 because the above var+=1 are for Test.var 
1 

編輯:關於我提到的'向前看'行爲。打算髮佈一個關於它的問題,但它在這個答案已經很好地解釋:https://stackoverflow.com/a/370380/1431750(以Python variable scope error

2

看看這些功能:

def f(): 
    var += 1 

def g(): 
    var = var.__iadd__(1) 

g是什麼f功能不(當然Python使用在第一個版本的INPLACE_ADD操作碼和不查找爲__iadd__屬性)文字版本。

但是,正如你所看到的,名字var被加載一次,在這兩個函數存儲一次。因此,如果您指定了一個變量,正如常見問題解答所說,它是本地的,除非您將其聲明爲全球第一。

那麼,你怎麼可以加載還不存在,總結1,然後用相同的名字再次存儲在本地變量?

類屬性的工作,因爲你正在做的:

Test.var = Test.var.__iadd__(1) 

varTest範圍確實存在(這樣可以擡起頭來,重新分配)。

0

本質上的規則是爲了避免歧義:

var = 0 # a variable in the global namespace 

class Test(): 
    var = 0 # this is a attribute of the Test class 

test = Test() 

def sum(): 
    Test.var += 1 
    test.var += 1 # these explicity mention on which object the name 
        # should be stored 

    blah = var # reads from a outer scope, but assigns to a local variable 
    var = Test # new local variable which shadows the outer name 
        # not great but understandable 

    var += 1 # this looks like it assigns to a local variable 
      # but since a name from a outer scope is read first, 
      # Python is not sure what the programmer really want to do 
      # (maybe assign to the outer scope, or first read it then shadow?) 
      # instead of guessing Python raises an exception, 
      # forcing the programmer to use `global` or a different name 
+0

「爲了避免模棱兩可,」在精神上是正確的,但最後一段不是關於如何'VAR + = 1相當準確'出錯了。 Python永遠不能將'var + = 1'解釋爲從全局變量讀取,然後寫入本地。它可以讀取和寫入全局變量,如果'全局變量'在播放,否則它將讀取和寫入本地'var'。如果在那一點上沒有*已經有一個本地'var',那麼你會得到一個關於試圖從一個不存在的變量中讀取的異常。 – Ben