10.1 函數的區域變數
在 Python 中,從變數創建的那一刻起到其作用域的結束(通常是宣告它的函數),變數是可以被訪問的。如果變數是在所有函數之外宣告的,那麼它被稱為全域變數。
在 Python 中,變數的作用域定義了變數可以使用的上下文。作用域幫助避免名稱衝突並管理數據訪問。Python 中的主要作用域類型包括:
區域作用域:在函數內創建的變數存在於該函數的區域作用域中,只能在該函數內部訪問。
嵌套函數的作用域:如果函數是在另一個函數內定義的,其變數僅在該嵌套函數內部可用。
全域作用域:在腳本或模組級別上定義的變數被視為全域的,可以從同一模組的任何部分訪問。
內建作用域:這是一個特殊的作用域,包含所有預設可用的 Python 內建對象和函數(例如,print() 和 len())。
LEGB 規則
為了解決變數,Python 使用 LEGB 規則,這個規則確定解釋器尋找變數的順序:
- L (Local) — 首先在區域作用域中尋找。
- E (Enclosed) — 然後在所有嵌套函數的作用域中尋找,從最近的到外部的。
- G (Global) — 接著在全域作用域中尋找。
- B (Built-in) — 最後在內建作用域中尋找。
使用範例
x = "global" # 全域變數
def outer():
y = "outer local" # 外層函數的區域變數
def inner():
z = "inner local" # 嵌套函數的區域變數
print(x) # 輸出 "global"
print(y) # 輸出 "outer local"
print(z) # 輸出 "inner local"
inner()
outer()
變數 z
只能在函數 inner()
內部訪問。
變數 y
可以在函數 outer()
和其內部宣告的所有函數中訪問。
變數 x
可在當前文件(模組)中的任何地方訪問。
10.2 存取全域變數: global x
Python 語言的一個有趣特性是,來自外部作用域的變數(嵌套當前作用域)只能被讀取。
當嘗試對外部變數進行賦值時,會創建一個同名的區域變數,從而失去對外部變數的訪問。
例子:
x = 10
def change_global():
print(x) # 這將引發錯誤,因為 x 在賦值後將被視為區域變數
x = 20 # 這裡會創建區域變數 x
print(x) # 輸出 20(存取的是區域變數 x)
change_global()
print(x) # 輸出 10
這個例子無法運作並會引發 UnboundLocalError
錯誤,因為 Python 直譯器首先看到的賦值 x = 20
,認為 x
為區域變數。然而,當直譯器走到 print(x)
時,找不到區域變數 x
,因為它尚未定義。
這是為了安全起見,以防區域變數意外更改全域變數。
global 運算符
如果你需要在函數內有意識地更改全域變數的值,可以使用 global
運算符。這個運算符允許明確地將更改作用於全域變數,而不是區域變數。
要在函數內更改全域變數的值,必須在函數開頭使用 global
宣告該變數。這讓函數可以寫入變數:
x = 10
def change_global():
global x # 宣告 x 為全域變數
print(x) # 輸出 10(存取的是全域變數 x)
x = 20 # 這裡給全域變數 x 賦予新值
print(x) # 輸出 20(存取的是全域變數 x)
change_global()
print(x) # 輸出 20
使用 global
運算符允許避免錯誤並正確管理全域變數。
全域變數可能會使程式變得不太可預測,且更難理解,因為它們的值可以在程式的任何地方被更改。當程式很大並由一組程式員開發時,這特別關鍵。
雖然有時使用全域變數不可避免,但最好盡量減少其使用。替代全域變數,考慮使用函數參數、返回值和類來儲存狀態。
使用全域變數可能導致意外的副作用,增加除錯和測試代碼的難度,也降低其重用性。因此建議謹慎使用全域變數,並僅在確實需要時使用。
10.3 存取非區域變數: nonlocal
除了全域和區域變數,Python 中還存在中間作用域的變數。例如,當函數嵌套在另一個函數中時。對於這類變數,可以使用 nonlocal
運算符。
nonlocal
運算符允許在嵌套函數中更改最近的作用域中的變數值,排除全域變數。
nonlocal
運算符幫助避免在嵌套函數中創建新的區域變數,當需要更改外部函數中定義的變數時。若不使用 nonlocal
,變更僅影響內部函數的區域變數,而不會影響外部函數的變數。
例子:
def outer():
count = 0
def inner():
nonlocal count
count += 1
return count
return inner
counter = outer()
print(counter()) # 輸出 1
下面是一個更實用的 nonlocal
使用範例,用於創建計數器:
def create_counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
counter = create_counter()
print(counter()) # 輸出 1
print(counter()) # 輸出 2
print(counter()) # 輸出 3
該例展示了如何在實際場景中使用 nonlocal
來創建一個在調用之間保持狀態的函數。
GO TO FULL VERSION