CodeGym /Java Adesua /Python SELF TW /變數的作用域

變數的作用域

Python SELF TW
等級 6 , 課堂 4
開放

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 來創建一個在調用之間保持狀態的函數。

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION