python中的做用域分4種狀況: L:local,局部做用域,即函數中定義的變量;
E:enclosing,嵌套的父級函數的局部做用域,即包含此函數的上級函數的局部做用域,但不是全局的;
G:globa,全局變量,就是模塊級別定義的變量; B:built-in,系統固定模塊裏面的變量,好比int, bytearray等。 搜索變量的優先級順序依次是:做用域局部>外層做用域>當前模塊中的全局>python內置做用域,也就是LEGB。python
1web 2閉包 3函數 4ui 5spa 6code 7ci |
|
固然,local和enclosing是相對的,enclosing變量相對上層來講也是local。
在Python中,只有模塊(module),類(class)以及函數(def、lambda)纔會引入新的做用域,其它的代碼塊(如if、try、for等)是不會引入新的做用域的,以下代碼:
1 2 3 4 |
|
這個是沒有問題的,if並無引入一個新的做用域,x仍處在當前做用域中,後面代碼可使用。
1 2 3 4 |
|
def、class、lambda是能夠引入新做用域的。
一個不在局部做用域裏的變量默認是隻讀的,若是試圖爲其綁定一個新的值,python認爲是在當前的局部做用域裏建立一個新的變量,也就是說在當前局部做用域中,若是直接使用外部做用域的變量,那麼這個變量是隻讀的,不能修改,如:
1 2 3 4 5 6 7 |
|
這裏第一個print中,使用到了外部做用域的count,這樣後面count就指外部做用域中的count了,再修改就會報錯。 若是沒使用過這個變量,而直接賦值,會認爲是新定義的變量,此時會覆蓋外部做用域中變量,如:
1 2 3 4 5 6 |
|
內部做用域中直接聲明瞭count=100,後面使用count都是內部做用域的了。
當內部做用域想修改外部做用域的變量時,就要用到global和nonlocal關鍵字了,當修改的變量是在全局做用域(global做用域)上的,就要使用global先聲明一下,代碼以下:
1 2 3 4 5 6 7 8 9 |
|
global關鍵字聲明的變量必須在全局做用域上,不能嵌套做用域上,當要修改嵌套做用域(enclosing做用域,外層非全局做用域)中的變量怎麼辦呢,這時就須要nonlocal關鍵字了
1 2 3 4 5 6 7 8 9 10 11 |
|
(1)變量查找順序:LEGB,做用域局部>外層做用域>當前模塊中的全局>python內置做用域;
(2)只有模塊、類、及函數才能引入新做用域;
(3)對於一個變量,內部做用域先聲明就會覆蓋外部變量,不聲明直接使用,就會使用外部做用域的變量;
(4)內部做用域要修改外部做用域變量的值時,全局變量要使用global關鍵字,嵌套做用域變量要使用nonlocal關鍵字。nonlocal是python3新增的關鍵字,有了這個關鍵字,就能完美的實現閉包了。