在python中,變數尋找遵循LGB原則,即優先在局部範圍(local scope)中對變數進行尋找,失敗則在全域範圍(global scope)中進行尋找,最後嘗試再內建範圍(build-in scope)內尋找,如果還是未找到的話,則拋出異常。後來由於閉包和嵌套函數的出現,範圍又增加了外部範圍,這樣變數的尋找範圍優先順序變為:局部、外部、全域和內建。 範圍由def、class、lambda等語句產生,if、try、for等語句並不會產生新的範圍。變數名引用分為三個範圍進行尋找:首先是本地,然後是函數內(如果有的話),之後是全域,最後是內建。在預設情況下,變數名賦值會建立或者改變本地變數。全域聲明將會給映射到模組檔案內部的範圍的變數名賦值。Python 的變數名解析機制也稱為 LEGB 法則,具體如下:當在函數中使用未確定的變數名時,Python 搜尋 4 個範圍:本地範圍(L),之後是上一層嵌套結構中 def 或 lambda 的本地範圍(E),之後是全域範圍(G),最後是內建範圍(B)。按這個尋找原則,在第一處找到的地方停止。如果沒有找到,Python 會報錯的。
a = 1def f(): a = 2def g(): print a //[1]:輸出結果為2return gfunc = f()func()//[2]
代碼的[2]處調用的函數實際上調用的是函數f 中定義的內嵌函數g,在代碼 的[1]處,函數g 內的“print a”的輸出結果為2。初看上去有些疑問,因為函數f 內的約束“a = 2”在其之外應該是不起作用的,當執行func()時,起作用的約束應該是“a = 1”才對。但是我們之前說到了,範圍僅僅是由文本決定的,函數g 位於函數f 之內,所以函數g 定義的範圍內嵌於函數f 的範圍之內。換句話說,函數f 的範圍是函數g 的範圍的直接外圍範圍,所以,按照最內嵌套範圍規則,[1]處的名字引用應該引用的是函數f 定義的範圍中所建立的約束。
儘管在代碼清單8-2 的[2]處,“a = 2”這個約束已經不起作用了,但是Python 在執行“func = f()”時,會執行函數f 中的“def g():”語句,這時Python 會將約束“a = 2”與函數g 對應的函數對象捆綁在一起,將捆綁後的結果返回,這個捆綁起來的整體被稱為“閉包”。
實際上這裡有一個相當微妙的問題,最內嵌套範圍規則是“閉包”的結果呢,還是“閉包”是最內嵌套範圍規則的實現方案。這兩個問題看上去是一致的,但卻隱含著誰決定誰的關係。實際上,Python 實現閉包是為了實現最內嵌套範圍規則。換句話說,最內嵌套範圍規則是語言設計時的設計策略,即是形而上的“道”;而閉包則實現語言時的一種方案,即是形而下的“器”。
python能夠改變變數範圍的程式碼片段是def、class、lamda. def scopetest(): localvar=6; print(localvar) scopetest() #print(localvar) #去除注釋這裡會報錯,因為localvar是本地變數 if/elif/else、try/except/finally、for/while while True: newvar=8 print(newvar) break; print(newvar) try: newlocal=7 raise Exception except: print(newlocal)#可以直接使用哦 輸出結果:8 8 7可見這個關鍵字中定義變數,他們的範圍跟外部是一致的,這個跟Java的範圍概念有點不一樣。 變數搜尋路徑是:本地變數->全域變數 def scopetest(): var=6; print(var)# var=5 print(var) scopetest() print(var) 輸出結果:5 6 5這裡var 首先搜尋的是本地變數,scopetest()中 var=6相當於自己定義了一個局部變數,賦值為6. 當然如果的確要修改全域變數的值,則需要如下: def scopetest(): global var var=6; print(var)# var=5 print(var) scopetest() print(var) 輸出結果:5 6 6再看一種這種情況: def scopetest(): var=6; print(var)# def innerFunc(): print(var)#look here innerFunc() var=5 print(var) scopetest() print(var) 輸出結果:5 6 6 5