什麼是Python變數作用域
在程式中定義一個變數時,這個變數是有作用範圍的,變數的作用範圍被稱為它的作用域。
根據定義變數的位置,變數分為兩種:
- 區域性變數:在函式中定義的變數,包括引數,都被稱為區域性變數。
- 全域性變數:在函式外面、全域性範圍內定義的變數,被稱為全域性變數。
每個函式在執行時,系統都會為該函式分配一塊“臨時記憶體空間”,所有的區域性變數都被儲存在這塊臨時記憶體空間內。當函式執行完成後,這塊記憶體空間就被釋放了,這些區域性變數也就失效了,因此離開函式之後就不能再訪問區域性變量了。
全域性變數意味著它們可以在所有函式內被訪問。
不管是在函式的區域性範圍內還是在全域性範圍內,都可能存在多個變數,每個變數“持有”該變數的值。從這個角度來看,不管是區域性範圍還是全域性範圍,這些變數和它們的值就像一個“看不見”的字典,其中變數名就是字典的 key,變數值就是字典的 value。
實際上,Python 提供瞭如下三個工具函式來獲取指定範圍內的“變數字典”:
globals():該函式返回全域性範圍內所有變數組成的“變數字典”。
locals():該函式返回當前區域性範圍內所有變數組成的“變數字典”。
vars(object):獲取在指定物件範圍內所有變數組成的“變數字典”。如果不傳入object 引數,vars() 和 locals() 的作用完全相同。
globals() 和 locals() 看似完全不同,但它們實際上也是有聯絡的,關於這兩個函式的區別和聯絡大致有以下兩點:
locals() 總是獲取當前區域性範圍內所有變數組成的“變數字典”,因此,如果在全域性範圍內(在函式之外)呼叫 locals() 函式,同樣會獲取全域性範圍內所有變數組成的“變數字典”;而 globals() 無論在哪裡執行,總是獲取全域性範圍內所有變數組成的“變數字典”。
一般來說,使用 locals() 和 globals() 獲取的“變數字典”只應該被訪問,不應該被修改。但實際上,不管是使用 globals() 還是使用 locals() 獲取的全域性範圍內的“變數字典”,都可以被修改,而這種修改會真正改變全域性變數本身:但通過 locals() 獲取的區域性範圍內的“變數字典”,即使對它修改也不會影響區域性變數。
下面程式示範瞭如何使用 locals()、globals() 函式訪問區域性範圍和全域性範圍內的“變數字典”:
def test (): age = 20 # 直接訪問age區域性變數 print(age) # 輸出20 # 訪問函式區域性範圍的“變數陣列” print(locals()) # {'age': 20} # 通過函式區域性範圍的“變數陣列”訪問age變數 print(locals()['age']) # 20 # 通過locals函式區域性範圍的“變數陣列”改變age變數的值 locals()['age'] = 12 # 再次訪問age變數的值 print('xxx',age) # 依然輸出20 # 通過globals函式修改x全域性變數 globals()['x'] = 19 x = 5 y = 20 print(globals()) # {...,'x': 5,'y': 20} # 在全域性訪問內使用locals函式,訪問的是全域性變數的“變數陣列” print(locals()) # {...,'y': 20} # 直接訪問x全域性變數 print(x) # 5 # 通過全域性變數的“變數陣列”訪問x全域性變數 print(globals()['x']) # 5 # 通過全域性變數的“變數陣列”對x全域性變數賦值 globals()['x'] = 39 print(x) # 輸出39 # 在全域性範圍內使用locals函式對x全域性變數賦值 locals()['x'] = 99 print(x) # 輸出99
從上面程式可以清楚地看出,locals() 函式用於訪問特定範圍內的所有變數組成的“變數字典”,而 globals() 函式則用於訪問全域性範圍內的全域性變數組成的“變數字典”。
全域性變數預設可以在所有函式內被訪問,但如果在函式中定義了與全域性變數同名的變數,此時就會發生區域性變數遮蔽(hide)全域性變數的情形。例如如下程式:
name = 'Charlie' def test (): # 直接訪問name全域性變數 print(name) # Charlie test() print(name)
上面程式中,第 4 行直接訪問 name 變數,這是允許的,此時程式將會輸出 Charlie。如果在此之後增加如下一行程式碼:
name = '孫悟空'
再次執行該程式,將會看到如下錯誤:
UnboundLocalError : local variable ‘name' referenced before assignment
該錯誤提示粗體字程式碼所訪問的 name 變數還未定義。這是什麼原因呢?這正是由於程式在 test() 函式中增加了“name='孫悟空'”一行程式碼造成的。
Python 語法規定,在函式內部對不存在的變數賦值時,預設就是重新定義新的區域性變數。因此這行程式碼相當於重新定義了 name 區域性變數,這樣 name 全域性變數就被遮蔽了,所以程式會報錯。
為了避免這個問題,可以通過以下兩種方式來修改上面程式:
訪問被遮蔽的全域性變數。如果希望程式依然能訪問 name 全域性變數,且在函式中可重新定義 name 區域性變數,也就是在函式中可以訪問被遮蔽的全域性變數,此時可通過 globals() 函式來實現,將上面程式改為如下形式即可:
name = 'Charlie' def test (): # 直接訪問name全域性變數 print(globals()['name']) # Charlie name = '孫悟空' test() print(name) # Charlie
在函式中宣告全域性變數。為了避免在函式中對全域性變數賦值(不是重新定義區域性變數),可使用 global 語句來宣告全域性變數。因此,可將程式改為如下形式:
name = 'Charlie' def test (): # 宣告name是全域性變數,後面的賦值語句不會重新定義區域性變數 global name # 直接訪問name全域性變數 print(name) # Charlie name = '孫悟空' test() print(name) # 孫悟空
增加了“global name”宣告之後,程式會把 name 變數當成全域性變數,這意味著 test() 函式後面對 name 賦值的語句只是對全域性變數賦值,而不是重新定義區域性變數。
知識點擴充套件:
python3 之 變數作用域
作用域: 指名稱空間可直接訪問的python程式的文字區域,這裡的 ‘可直接訪問' 意味著:對名稱的引用(非限定),會嘗試在名稱空間中查詢名稱;
- L:local,區域性作用域,即函式中定義的變數;
- E:enclosing,巢狀的父級函式的區域性作用域,即包含此函式的上級函式的區域性作用域,但不是全域性的;
- G:globa,全域性變數,就是模組級別定義的變數;
- B:built-in,內建作用域,系統固定模組裡面的變數,比如:int,bytearray等
到此這篇關於什麼是Python變數作用域的文章就介紹到這了,更多相關Python變數作用域詳解內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!