標籤:逗號 color print font 變數 原來 部分 def 對象
在Python中,一個變數的scope範圍從小到大分成4部分:Local Scope(也可以看成是當前函數形成的scope),Enclosing Scope(簡單來說,就是外層函數形成的scope),Global Scope(就是當前檔案形成的scope),Builtins Scope(簡單來說,就是Python內建的變數位於最頂層的scope)。當Python開始尋找一個非限定的變數名時(像obj.attr中的attr,就是一個被限定的變數名字,它被限定在obj對象中,而普通的變數名就是沒有限定的),總是從當前變數名所處的scope開始,順著前面提到的scope鏈開始往上尋找,一旦尋找到就不會往上再繼續尋找,如果尋找完整個scope鏈還是沒找到,Python會報錯。
上面提到的變數名尋找順序,可以簡單的記為LEGB(每一個scope的首字母),而global和nonlocal,可以改變尋找順序。
global
在檔案中聲明的變數自動成為global的,而如果想在一個函數裡面聲明一個全域變數,就需要使用global關鍵字:
global var1, var2, ... # 多個變數用逗號隔開
對於global關鍵字,需要注意以下幾點:
1 當Python看到一個變數由global變數聲明,開始尋找的scope不是從這個變數當前所在的scope開始尋找,而是從Global Scope開始尋找;如果Global Scope沒有找到,就會繼續到Builtins Scope尋找;
2 global關鍵字聲明的對象允許賦值,如果這個變數之前不存在,那麼,這次賦值就是建立了一個全域變數;如果這個變數之前存在,那麼,這次賦值就改變了這個全域變數的值:
def test(): global x x = 1 # x之前不存在,因此在Global Scope建立了一個全域變數xx = 1def test(): global x x = 99 # x之前在Global Scope中已經存在,因此這裡是改變x的值
3 只要被global關鍵字聲明的變數,都會成為全域變數,如果該變數原來不是全域變數,也會如此,並且,如果之前Global Scope裡面有同名變數,那麼被global聲明的變數會取代這個同名變數:
x = 99def test(): x = 88 global x # 這樣做的話Python會產生警告:SyntaxWarning: name ‘x‘ is assigned to before global declaration>>>print(x) # 一開始訪問的是全域變數x>>>99>>>test() # 執行test函數之前,原本函數裡面的局部變數x成為了全域變數,並取代原來的全域變數>>>print(x) # 現在訪問的是取代後的全域變數x,值變為88>>>88# 在看一個例子,加入開始沒有定義全域變數xdef test(): x = 88 global x # 仍會產生相同的警告>>>test()>>>print(x) # 列印結果為88!!!>>>88
nonlocal
nonlocal是Python 3.X加入進來的關鍵字,Python 2.X中沒有。在Python中,嵌套函數是可以訪問外部函數的變數的(至少在>Python 2.2的版本是這樣的,在Python 2.2之前的版本中,變數的尋找從當前函數開始,然後直接到Global Scope,Builtins Scope,跳過了外層函數),但是卻不可以改變外部函數變數的值,如果確實要改變,就的使用nonlocal變數進行聲明:
nonlocal var1, var2,... # 只在Python 3.X中支援,多個變數用逗號隔開
對於nonlocal關鍵字,需要注意以下幾點:
1 nonlocal關鍵字只在Python 3.X中支援,Python 2.X沒有這個關鍵字;
2 nonlocal關鍵字只可以在函數內部使用,在其他地方使用會報錯;
3 nonlocal聲明的變數,之前必須已經存在(並且是在外部函數中存在),如果變數不存在就對這個變數賦值,會報錯,這點和global關鍵字不一樣:
# 變數存在於Global Scopex = 99def test(): nonlocal x # 報錯:SyntaxError: name ‘x‘ is assigned to before nonlocal declaration# 變數存在於當前函數def test(): x = 99 nonlocal x # 報錯:SyntaxError: name ‘x‘ is assigned to before nonlocal declaration
4 對於nonlocal聲明的變數,只會在外部函數中尋找該變數,不會在Global Scope和Builtins Scope中尋找
Python中的global和nonlocal