1、典型案例
代碼1:塊作用域
if True: i = 1 print i
執行結果: 1
代碼2:函數作用域
def f(): i = 1 f() print i
執行結果:執行報錯“NameError: name 'cc' is not defined”
代碼3:靜態作用域
i = 1 def test(): i += 1 test()
執行結果:執行報錯“UnboundLocalError: local variable 'i' referenced before assignment”
代碼4:靜態作用域
i = 1 def g(): print i def f(): i = 2 g() f()
執行結果: 1
代碼5:閉包、全局作用域
i = 1 def f(): i = 2 def g(): print i return g func = f() func() print i
執行結果:2 1
PS:python2.1之前執行該代碼會報錯,閉包(嵌套作用域)是在之后引入的概念,內部函數g()只能訪問本函數中的命名空間、全局命名空間、內建命名空間,無法訪問外部調用函數的命名空間。
2、命名空間
【定義】
名稱到對象的映射。命名空間是一個字典的實現,鍵為變量名,值是變量對應的值。各個命名空間是獨立沒有關系的,一個命名空間中不能有重名,但是不同的命名空間可以重名而沒有任何影響。
【分類】
python程序執行期間會有2個或3個活動的命名空間(函數調用時有3個,函數調用結束后2個)。按照變量定義的位置,可以划分為以下3類:
Local,局部命名空間,每個函數所擁有的命名空間,記錄了函數中定義的所有變量,包括函數的入參、內部定義的局部變量。
Global,全局命名空間,每個模塊加載執行時創建的,記錄了模塊中定義的變量,包括模塊中定義的函數、類、其他導入的模塊、模塊級的變量與常量。
Built-in,python自帶的內建命名空間,任何模塊均可以訪問,放着內置的函數和異常。
【生命周期】
Local(局部命名空間)在函數被調用時才被創建,但函數返回結果或拋出異常時被刪除。(每一個遞歸函數都擁有自己的命名空間)。
Global(全局命名空間)在模塊被加載時創建,通常一直保留直到python解釋器退出。
Built-in(內建命名空間)在python解釋器啟動時創建,一直保留直到解釋器退出。
各命名空間創建順序:python解釋器啟動 ->創建內建命名空間 -> 加載模塊 -> 創建全局命名空間 ->函數被調用 ->創建局部命名空間
各命名空間銷毀順序:函數調用結束 -> 銷毀函數對應的局部命名空間 -> python虛擬機(解釋器)退出 ->銷毀全局命名空間 ->銷毀內建命名空間
python解釋器加載階段會創建出內建命名空間、模塊的全局命名空間,局部命名空間是在運行階段函數被調用時動態創建出來的,函數調用結束動態的銷毀的。
3、作用域
【定義】
作用域是針對變量而言,指申明的變量在程序里的可應用范圍。或者稱為變量的可見性。
【分類】
只有函數、類、模塊會產生作用域,代碼塊不會產生作用域(參考代碼1)。作用域按照變量的定義位置可以划分為4類:
Local(函數內部)局部作用域
Enclosing(嵌套函數的外層函數內部)嵌套作用域(閉包)
Global(模塊全局)全局作用域
Built-in(內建)內建作用域
【規則】
1、靜態作用域規則
定義:python中變量的作用域是由它在源代碼中的位置決定的。(名字查找是動態發生的)
說明:參考代碼3/4,以代碼3為例說明,在模塊中定義了一個全局變量 i = 1,在test方法中執行 i += 1,對變量 i進行了賦值動作,該賦值動作決定了i在test()方法中是一個局部變量, i += 1可以拆分為兩步執行,首先執行 i + 1, 然后將結果賦值給i。執行i + 1操作時,i雖然申明為局部變量,但是沒有綁定任何具體值,因此報錯。
2、最內嵌套作用域規則
定義:由一個賦值語句引進的名字在這個賦值語句所在的作用域里是可見(起作用)的,而且在其內部嵌套的每個作用域內也可見,除非它被嵌套於內部的且引進同樣名字的賦值語句所遮蔽。
說明:參考代碼5. 方法g()是方法f()中定義的內嵌函數。在方法f()中定義的局部變量 i =2,在內嵌方法 g()中是可見的。如果在g()中又定義一個重名的變量 i = 3,則f()中定義的變量將被遮蔽。
4、命名空間與作用域的關系
命名空間定義了在某個作用域內變量名和綁定值之間的對應關系,命名空間是鍵值對的集合,變量名與值是一一對應關系。作用域定義了命名空間中的變量能夠在多大范圍內起作用。
命名空間在python解釋器中是以字典的形式存在的,是以一種可以看得見摸得着的實體存在的。作用域是python解釋器定義的一種規則,該規則確定了運行時變量查找的順序,是一種形而上的虛的規定。
【變量查找法則】
python解釋器動態執行過程中,對遇到的變量進行解釋時,是按照一條固定的作用域鏈查找解釋的,又稱為LEGB法則。
其中L代表Local 局部作用域,E代表Enclosing 嵌套作用域,G代表Global 全局作用域,B代表Built-in 內建作用域。
python解釋器查找變量時,會按照順序依次查找局部作用域,嵌套作用域,全局作用域,內建作用域,在任意一個作用域中找到變量則停止查找,所有作用域查找完成沒有找到對應的變量,則拋出 NameError: name 'xxxx' is not defined的異常。
在局部作用域中,可以看到局部作用域、嵌套作用域、全局作用域、內建作用域中所有定義的變量。
在全局作用域中,可以看到全局作用域、內建作用域中的所有定義的變量,無法看到局部作用域中的變量。