在上一篇文章中,我們介紹了 命名空間 (Namespace),了解了名稱與對象如何被儲存與管理。
不過,光知道名稱存在哪裡還不夠,程式還需要一套規則來決定「在什麼位置可以使用這些名稱」。這就是 作用域 (Scope) 的任務。
作用域定義了名稱的可見範圍與存活時間。無論是函數中的局部變數、模組中的全域變數,還是 Python 內建的函數,程式在執行時會依照特定的搜尋順序來解析它們。
作用域 (Scope) 介紹
作用域定義了程式在不同部分可以訪問哪些命名空間,以及訪問的順序。
作用域決定了我們程式中哪些名稱可以被訪問
多個命名空間可能同時存在,但並非所有命名空間在程式的各個部分都可訪問
與命名空間類似,Python 有四種不同層級的作用域:內建作用域、全域作用域、封閉作用域和局部作用域
命名空間是存儲名稱-對象對的機制,而作用域則是一套規則系統,決定在程式的哪些位置可以檢索這些名稱。

局部作用域 (Local Scope)
局部作用域的特點:
- 每次呼叫函數時產生
- 是最深層的作用域
- 局部作用域中的名稱不能被外部作用域訪問或修改
- 通常與局部命名空間一一對應
局部作用域限制了變數的可見性,防止不同函數間的變數互相干擾。
def favorite_color():
color = 'Red'
print(color) # 錯誤!
# 正確做法:
def favorite_color():
color = 'Red'
print(color) # 正確
favorite_color()
第一個例子中,print(color)
在函數外部,無法訪問函數內的局部作用域。
第二個例子中,print(color)
在函數內部,可以訪問到局部變數 color
。
封閉/非局部作用域 (Enclosing/Nonlocal Scope)
封閉作用域(也稱為非局部作用域)允許嵌套函數訪問外部函數中定義的值。
def outer_function():
enclosing_value = 'Enclosing Value'
def nested_function():
nested_value = 'Nested Value'
print(enclosing_value) # 可以訪問外部函數的變數
nested_function()
outer_function()
封閉作用域有兩個重要限制:
單向流動
作用域訪問只能向上流動。內部函數可以訪問外部函數的變數,但外部函數不能訪問內部函數的變數。
不可修改性
內部函數可以訪問外部函數的不可變對象(如字符串或數字),但無法直接修改它們。
修改作用域行為:nonlocal 語句
Python 提供了 nonlocal 語句,允許我們在嵌套函數中修改外部函數中定義的變數。
不使用 nonlocal:
def enclosing_function():
var = "value"
def nested_function():
var = "new_value" # 創建新的局部變數
nested_function()
print(var) # 輸出 "value"
enclosing_function()
這裡的 var = "new_value"
只是在內部函數中創建了一個新的局部變數,而不是修改外部函數中的 var
。
使用 nonlocal:
def enclosing_function():
var = "value"
def nested_function():
nonlocal var
var = "new_value" # 修改外部變數
nested_function()
print(var) # 輸出 "new_value"
enclosing_function()
使用 nonlocal
關鍵字後,內部函數可以修改外部函數中定義的變數。
全域作用域 (Global Scope)
全域作用域的特點:
- 全域作用域是最高級別的訪問層級
- 全域命名空間中定義的名稱自動具有全域作用域
- 全域作用域的名稱可以在程式的任何地方訪問
- 與封閉作用域類似,默認情況下全域變數可以被訪問但不能被修改
# 全域變數
gravity = 9.8
def get_force(mass):
return mass * gravity # 訪問全域變數
print(get_force(60)) # 輸出 588.0
全域變數像重力一樣,在整個程式中都有影響,但在局部作用域中嘗試修改它會導致錯誤。
修改作用域行為:global 語句
Python 提供了 global 語句,允許在局部作用域中修改全域變數。
不使用 global
global_var = 10
def some_function():
global_var = 20 # 創建局部變數
some_function()
print(global_var) # 輸出 10
使用 global
global_var = 10
def some_function():
global global_var
global_var = 20 # 修改全域變數
some_function()
print(global_var) # 輸出 20
此外,即使全域命名空間中尚未定義某個名稱,也可以使用 global
語句在全域命名空間中創建它:
def some_function():
global x # 在全域命名空間中創建 x
x = 30
some_function()
print(x) # 輸出 30
作用域解析:LEGB 規則
作用域解析是描述 Python 在各種命名空間中搜索名稱的過程。Python 遵循 LEGB 規則,按以下順序搜索名稱:
L (Local)
最先搜索局部作用域(函數內部)
E (Enclosing)
如果在局部找不到,則搜索封閉作用域(外部函數)
G (Global)
如果在封閉作用域找不到,則搜索全域作用域
B (Built-in)
最後搜索內建作用域(Python 預定義的名稱)
如果在這四個作用域中都找不到名稱,Python 會返回 NameError
異常。

LEGB 規則:實例演示
情況 1:名稱在全域作用域中
age = 27
def func():
def inner_func():
print(age) # 使用全域變數
inner_func()
func() # 輸出 27
搜索順序:
1. 在 inner_func() 的局部作用域中搜索 age
2. 在 func() 的封閉作用域中搜索 age
3. 在全域作用域中找到 age
情況 2:名稱在多個作用域中
age = 27
def func():
age = 42 # 在封閉作用域中定義 age
def inner_func():
print(age) # 使用最近的 age
inner_func()
func() # 輸出 42
搜索順序:
1. 在 inner_func() 的局部作用域中搜索 age
2. 在 func() 的封閉作用域中找到 age,值為 42
3. 不繼續往上搜索
結語
作用域 (Scope) 就像是 Python 的搜尋指南,決定了名稱在哪裡可見、在哪裡不可見。
透過 Local、Enclosing、Global、Built-in 四個層級,Python 建立了一套嚴謹的規則,避免變數互相干擾,也讓程式更具結構性。
理解作用域能幫助你更好地排查錯誤,例如 NameError
或「變數值不如預期」的情況;同時也能讓你靈活運用 global
與 nonlocal
關鍵字,在需要時修改變數的作用範圍。
