目次
1. 前言:什麼是 Python 的變數作用域?
在學習 Python 的過程中,常常會遇到「變數的作用域(Scope)」這個概念。作用域是指變數可以被存取的範圍,如果沒有正確理解,可能會導致預期之外的錯誤或 Bug。 例如,請看看下面這段程式碼:def my_function():
x = 10 # 這個變數 x 僅在函式內部有效
print(x) # NameError: name 'x' is not defined這段程式碼中,試圖在函式 my_function 外部參考裡面定義的變數 x,結果導致錯誤。這是因為x 屬於「區域作用域」(Local Scope),在函式外部就不存在。 本文將從 Python 的變數作用域基礎開始,詳細解說進階用法與錯誤排除方法,幫助你正確理解與管理作用域。Ad
2. 變數作用域的基本概念
2.1 什麼是變數作用域?
變數作用域是指變數可以被使用的範圍。在 Python 中,變數定義的位置會決定它可以被參考的範圍。 例如,在函式內定義的變數無法在函式外部存取。相對地,在模組層級定義的變數可以在整個腳本中使用。2.2 為什麼要理解作用域?
如果沒有正確管理變數作用域,可能會導致以下問題:- 不小心覆蓋變數 在不同作用域中使用相同名稱的變數,可能會造成預期外的 Bug。
- 找不到變數(NameError) 如果不了解作用域規則,試圖存取未定義的變數,就會出現
NameError。 - 程式可讀性降低 過度使用全域變數會讓程式邏輯變得不清晰,也更難除錯。
2.3 Python 作用域的基本規則
為了正確理解 Python 的作用域,請掌握以下幾個要點:- 函式內定義的變數只在該函式內有效(區域作用域)
- 函式外定義的變數可在整個腳本中使用(全域作用域)
- Python 使用「LEGB 規則」來決定變數的搜尋順序
- 若要在函式中修改全域變數,需使用
global關鍵字 - 若要在巢狀函式中修改外層變數,需使用
nonlocal關鍵字
3. Python 的作用域種類與範例
在 Python 中,變數的作用域大致可分為 四種類型。了解每一種作用域的特性並正確管理變數,是撰寫無錯誤程式碼的關鍵。- 區域作用域(Local Scope)
- 包覆作用域(Enclosing Scope)
- 全域作用域(Global Scope)
- 內建作用域(Built-in Scope)
3.1 區域作用域(Local Scope)
區域作用域是指在函式內部定義的變數所擁有的作用範圍。這些變數只在該函式內有效,無法在函式外部存取。區域作用域範例
def my_function():
x = 10 # x 是此函式的區域變數
print(x) # 這行會正常執行
my_function()
print(x) # NameError: name 'x' is not defined說明: 變數 x 僅在 my_function 執行期間有效,函式外部無法存取,否則會出現 NameError。3.2 包覆作用域(Enclosing Scope)
包覆作用域是指巢狀函式中外層函式的變數作用範圍。內部函式(子函式)可以存取外部函式(父函式)中定義的變數。包覆作用域範例
def outer_function():
y = 20 # 父函式中的變數
def inner_function():
print(y) # 子函式可以存取父函式的變數
inner_function()
outer_function()說明: inner_function 可以存取 outer_function 中的變數 y,這就是包覆作用域的特性。3.3 全域作用域(Global Scope)
全域作用域是指整個模組(腳本)中都可以存取的變數作用範圍。在函式外部定義的變數,任何地方都能參考。全域作用域範例
z = 30 # 全域變數
def my_function():
print(z) # 可以存取全域變數
my_function()
print(z) # 在任何地方都可存取3.4 內建作用域(Built-in Scope)
內建作用域是指Python 預設提供的內建函式與變數所屬的作用域。例如print()、len() 等函式即屬於此範圍。內建作用域範例
print(len([1, 2, 3])) # 輸出:3說明: print 與 len 是 Python 的內建函式,無論在哪個作用域都可以使用。3.5 四種作用域總結
| 作用域名稱 | 說明 | 範例 |
|---|---|---|
| 區域作用域 | 僅在函式內部有效的變數 | 函式內的變數 |
| 包覆作用域 | 可由巢狀函式存取外層函式的變數 | 巢狀函式中的變數 |
| 全域作用域 | 整個腳本中皆可參考的變數 | global 變數 |
| 內建作用域 | Python 內建函式與變數 | print(), len() |
Ad
4. 變數作用域的查找順序(LEGB 規則)
在 Python 中,當你參考某個變數時,會依照特定的順序來查找變數。這個查找順序稱為 LEGB 規則(Local、Enclosing、Global、Built-in),查找順序如下:- L(Local)區域作用域 – 目前函式內定義的變數
- E(Enclosing)包覆作用域 – 外層(巢狀)函式中定義的變數
- G(Global)全域作用域 – 模組層級定義的變數
- B(Built-in)內建作用域 – Python 預設提供的內建函式與變數
4.1 LEGB 規則的範例
x = "全域變數" # G(Global)
def outer_function():
x = "包覆變數" # E(Enclosing)
def inner_function():
x = "區域變數" # L(Local)
print(x) # 根據 LEGB 規則,會參考最內層的 x
inner_function()
outer_function()
print(x) # 參考全域作用域的 x執行結果
區域變數
全域變數4.2 全域作用域的影響
當你在函式內試圖修改一個全域變數時,如果沒有使用global 關鍵字,Python 會認為你是在定義區域變數,這可能導致 UnboundLocalError 錯誤。錯誤示範:在區域作用域中修改全域變數
x = 10 # 全域變數
def update_x():
x += 1 # 發生錯誤
print(x)
update_x()錯誤訊息
UnboundLocalError: local variable 'x' referenced before assignment解決方式:使用 global 關鍵字
x = 10 # 全域變數
def update_x():
global x # 明確指定為全域變數
x += 1
print(x)
update_x() # 輸出:114.3 使用 nonlocal 修改包覆作用域的變數
如果你想在巢狀函式中修改外層函式的變數(也就是 E 的部分),需要使用 nonlocal 關鍵字。nonlocal 使用範例
def outer_function():
count = 0 # 外層函式中的變數
def inner_function():
nonlocal count # 指定要使用外層函式的變數
count += 1
print(count)
inner_function()
print(f"最終計數:{count}")
outer_function()執行結果
1
最終計數:14.4 查找內建作用域的函式
Python 內建許多常用函式,如print()、len() 等,這些函式存在於最外層的 內建作用域(Built-in Scope)。覆蓋內建函式的錯誤範例
sum = 100 # `sum()` 是內建函式,但被變數覆蓋
print(sum([1, 2, 3])) # TypeError: 'int' object is not callable解決方式:刪除覆蓋的變數
del sum # 移除覆蓋的變數
print(sum([1, 2, 3])) # 正常執行4.5 LEGB 規則總結
| 作用域 | 說明 | 範例 |
|---|---|---|
| L(Local) | 函式內定義的變數 | def func(): x = 1 |
| E(Enclosing) | 外層函式中定義的變數 | 巢狀函式中的外層變數 |
| G(Global) | 模組層級(函式外)定義的變數 | x = 10 |
| B(Built-in) | Python 內建函式與變數 | print(), len() |
5. 全域變數與區域變數的使用時機
在 Python 中,正確管理變數的全域作用域與區域作用域非常重要。若濫用全域變數,會降低程式的可讀性,並提高產生錯誤的風險。 本節將詳細說明全域變數與區域變數的差異,以及如何正確使用。5.1 什麼是全域變數?
全域變數(Global Variable) 是指在函式外部定義,整個腳本中都可以參考的變數。全域變數範例
count = 0 # 全域變數
def increment():
global count # 使用全域變數
count += 1
increment()
print(count) # 輸出:15.2 什麼是區域變數?
區域變數(Local Variable) 是指在函式內部定義,只在該函式內有效的變數。區域變數範例
def my_function():
x = 10 # 區域變數
print(x)
my_function()
print(x) # NameError: name 'x' is not defined5.3 什麼情況應該使用 global 關鍵字?
通常應該儘量避免使用全域變數,但在某些特定情況下,使用 global 是合適的。適用情況
- 用來管理設定值或常數
- 當需要在多個函式之間共享變數時
範例:管理設定值
MAX_USERS = 100 # 全域變數(作為常數使用)
def print_max_users():
print(f"最大使用者數量:{MAX_USERS}")
print_max_users() # 輸出:最大使用者數量:1005.4 不使用 global 管理變數的方法
與其使用全域變數,不如善用函式的參數與回傳值,這樣可以更安全地管理資料。使用函式參數與回傳值
def increment(value):
return value + 1
counter = 0
counter = increment(counter) # 接收回傳值
print(counter) # 輸出:15.5 全域變數與區域變數的比較總結
| 項目 | 全域變數 | 區域變數 |
|---|---|---|
| 定義位置 | 函式外部 | 函式內部 |
| 存取範圍 | 整個腳本皆可使用 | 僅限於定義的函式內 |
| 變更影響 | 可能影響所有函式 | 影響範圍較小 |
| 優點 | 可在任何地方存取 | 提升函式獨立性 |
| 缺點 | 變更難以追蹤 | 無法在函式外使用 |
| 建議用法 | 用於常數或設定值 | 盡量使用區域變數 |
Ad
6. 巢狀函式與 nonlocal 關鍵字
在 Python 中,可以在一個函式內部定義另一個函式,這稱為巢狀(嵌套)函式。善用巢狀函式可以讓程式結構更清晰,同時更細緻地管理變數作用域。 如果你想在巢狀函式中修改外層函式的變數,就需要使用nonlocal 關鍵字。本節將詳細說明 nonlocal 的用途與使用方法。6.1 什麼是巢狀函式?
巢狀函式(Nested Function) 是指在函式內部定義的函式。巢狀函式範例
def outer_function():
def inner_function():
print("這是內部函式")
inner_function() # 在外部函式中呼叫內部函式
outer_function() # 輸出:這是內部函式6.2 使用 nonlocal 修改外層變數
一般情況下,內部函式無法直接修改外部函式的變數。如果這樣做會發生錯誤。錯誤範例
def outer_function():
count = 0 # 外部函式的變數
def inner_function():
count += 1 # 發生錯誤
print(count)
inner_function()
outer_function()解決方式:使用 nonlocal 關鍵字
def outer_function():
count = 0 # 外部函式的變數
def inner_function():
nonlocal count # 指定使用外層函式的變數
count += 1
print(count)
inner_function()
print(count) # 內部修改後的值會反映到這裡
outer_function()執行結果
1
16.3 global 和 nonlocal 的差異
| 關鍵字 | 影響的作用域 | 用途說明 |
|---|---|---|
| global | 整個模組的全域變數 | 從函式內部修改全域變數 |
| nonlocal | 外層函式的變數(包覆作用域) | 在巢狀函式中修改外層變數 |
global 範例
count = 0 # 全域變數
def increment():
global count # 修改全域變數
count += 1
increment()
print(count) # 輸出:1nonlocal 範例
def outer():
count = 0 # 包覆作用域中的變數
def inner():
nonlocal count # 修改外層函式的變數
count += 1
inner()
print(count) # 輸出:1
outer()✅ global 用於修改全域變數。 ✅ nonlocal 用於在巢狀函式中修改外層變數。Ad
7. 常見的作用域錯誤與解決方式
如果對 Python 的作用域理解不夠深入,可能會遇到以下問題:「變數未定義」、「意外改變變數的值」、「作用域使用錯誤」 等。 本節將說明與作用域相關的常見錯誤原因及其對應的解決方法。7.1 UnboundLocalError:在指定前參考變數
錯誤範例
count = 0 # 全域變數
def increment():
count += 1 # 這裡會發生錯誤
print(count)
increment()錯誤訊息
UnboundLocalError: local variable 'count' referenced before assignment解決方案 ①:使用 global 關鍵字
count = 0 # 全域變數
def increment():
global count # 明確指定使用全域變數
count += 1
print(count)
increment() # 輸出:1解決方案 ②:使用函式參數
def increment(count):
return count + 1
count = 0
count = increment(count)
print(count) # 輸出:17.2 NameError:變數未定義
錯誤範例
def print_message():
print(message) # 這裡會發生錯誤
print_message()錯誤訊息
NameError: name 'message' is not defined解決方式
請在函式中定義變數,或透過參數傳入。def print_message(message):
print(message)
print_message("你好") # 輸出:你好7.3 TypeError:使用與內建函式同名的變數
如果你定義的變數名稱與 Python 的內建函式相同,呼叫該函式時可能會發生 TypeError。錯誤範例
sum = 100 # 覆蓋了內建函式 sum()
print(sum([1, 2, 3])) # 這裡會發生錯誤錯誤訊息
TypeError: 'int' object is not callable解決方式
- 更改變數名稱
total = 100 # 使用 total 代替 sum
print(sum([1, 2, 3])) # 正常執行- 刪除被覆蓋的內建函式
sum = 100
del sum # 解除覆蓋
print(sum([1, 2, 3])) # 正常執行7.4 預防作用域錯誤的最佳做法
✅ 盡可能使用區域變數(限制作用範圍可避免意外變更) ✅ 不要在函式內部修改全域變數(避免使用global,建議使用參數與回傳值)
✅ 確認未使用與內建函式相同的變數名稱 ✅ 清楚規劃變數的作用範圍,並選擇適當的作用域Ad
8. 正確管理作用域的實用技巧
妥善管理 Python 的作用域對於提升程式可讀性與避免錯誤來說非常重要。特別是濫用全域變數或管理不當,會導致程式行為異常並增加除錯難度。 本節將介紹幾個實用的建議,幫助你更好地管理作用域。8.1 儘量減少全域變數的使用
全域變數可以在任何地方被存取,這使得變數容易被意外修改。因此,建議將全域變數的使用降到最低。錯誤示範:過度使用全域變數
counter = 0 # 全域變數
def increment():
global counter # 修改全域變數
counter += 1
increment()
print(counter) # 輸出:1正確示範:使用參數與回傳值
def increment(value):
return value + 1
counter = 0
counter = increment(counter)
print(counter) # 輸出:18.2 清晰定義函式的作用域
透過適當管理函式內的變數範圍,可以限制變數的影響範圍,防止意外修改。良好範例:活用區域變數
def calculate_square(number):
result = number ** 2 # 區域變數
return result
print(calculate_square(4)) # 輸出:168.3 正確使用 global 與 nonlocal
使用 global 的合適情境
- 用於設定值或常數的管理
- 需要保留狀態的變數(例如:單例模式)
MAX_USERS = 100 # 全域變數(作為常數)
def get_max_users():
return MAX_USERS
print(get_max_users()) # 輸出:100使用 nonlocal 的合適情境
- 在巢狀函式中需要修改外層函式的變數時
def outer():
count = 0 # 外層函式變數
def inner():
nonlocal count # 修改外層變數
count += 1
print(count)
inner()
outer() # 輸出:18.4 作用域管理檢查清單
✅ 函式內部使用的變數,是否都用區域變數? ✅ 全域變數是否真的有必要?是否可以改用函式參數? ✅ 函式間傳遞資料是否使用了參數與回傳值? ✅ 是否過度使用global 或 nonlocal? ✅ 是否使用了與內建函式相同的變數名稱? ✅ 是否有意識地規劃變數的作用範圍? 善用這份檢查清單,可以幫助你在撰寫程式時避免作用域相關的問題,寫出更安全且易於維護的程式碼。Ad
9. FAQ(常見問題與解答)
本節整理了關於 Python 變數作用域的常見問題, 透過問與答的形式解說,幫助你釐清誤解,深化實務理解。9.1 不使用 global,要如何管理全域變數?
A:可透過函式的參數與回傳值來處理變數,避免修改全域變數。
def increment(value):
return value + 1
count = 10
count = increment(count)
print(count) # 輸出:11✅ 這種作法讓函式更獨立,也提升了重用性。9.2 nonlocal 和 global 有什麼不同?
A: nonlocal 是用來修改「包覆作用域」中的變數。
| 關鍵字 | 影響的作用域 | 使用場景 |
|---|---|---|
| global | 全域作用域 | 在函式內修改模組層級的變數 |
| nonlocal | 包覆作用域(外層函式) | 在巢狀函式中修改外層函式的變數 |
nonlocal 的範例
def outer():
count = 0 # 外層函式的變數
def inner():
nonlocal count # 修改外層變數
count += 1
inner()
print(count) # 輸出:1
outer()9.3 什麼是 LEGB 規則?
A:這是 Python 在搜尋變數時所依循的優先順序。
- L(Local): 函式內部定義的變數
- E(Enclosing): 巢狀函式的外層函式變數
- G(Global): 模組層級的變數
- B(Built-in): Python 的內建函式
LEGB 規則範例
x = "全域變數" # G
def outer():
x = "包覆變數" # E
def inner():
x = "區域變數" # L
print(x) # 根據 LEGB 規則,會輸出最內層的變數
inner()
outer()
print(x) # 參考全域變數✅ 理解 LEGB 規則,有助於掌握 Python 的變數解析機制。Ad
10. 總結
本文詳細說明了 Python 中的變數作用域(Scope)。透過理解與正確管理作用域,你可以避免 Bug 並撰寫更具可讀性的程式碼。10.1 Python 作用域的基本概念
✅ 什麼是作用域?- 決定變數可被存取範圍的規則。
- 區域作用域(函式內)與全域作用域(函式外)是最基本的分類。
- 防止變數被意外覆蓋。
- 避免變數未定義錯誤(如
NameError)。 - 提升程式碼的可讀性與除錯效率。
10.2 Python 的四種作用域
Python 中有4 種作用域,變數的搜尋順序依照LEGB 規則:| 作用域 | 說明 | 範例 |
|---|---|---|
| L(Local) | 函式內定義的變數 | def func(): x = 1 |
| E(Enclosing) | 外層函式中定義的變數 | 巢狀函式使用外層變數 |
| G(Global) | 整個模組中都可使用的變數 | x = 10(函式外) |
| B(Built-in) | Python 預設提供的函式與變數 | print(), len() |
10.3 global 與 nonlocal 的正確用法
✅ 使用 global 的情境:- 需要集中管理設定值或常數
- 在多個函式中共用相同變數
nonlocal 的情境:- 在巢狀函式內修改外層函式的變數



