變數範圍

全域變數與區域變數

提到函式,便不得不談到變數的有效範圍,也就是變數被認定(認識)的範圍。

  • 定義在函式外的變數其範圍是一整個 Python 檔案,又稱 全域變數(全域指的是整個 Python 檔)
  • 定義在一個函式中的變數稱為區域變數,其範圍是一整個函式

而以上兩種範圍都必須從變數定義被 Python 看到開始算起,若是區域變數與全域變數名稱相同產生衝突時,區域內以區域變數為主,區域外以全域變數為主。

我們來看個例子:

def test_scope():
    var1 = 1
    print(var1, var2)

var1 = 0
var2 = 0

test_scope()
print(var1, var2)

最後印出的結果是:

1 0
0 0

我們發現 var1 雖然在函式外有定義過,但是在函式中,由於我們也定義了一個區域函數,所以在印出 var1 的時候,Python 會優先選擇在函式中的定義,反觀 var2,由於區域內沒有定義所以會去選擇函式外的全域變數。

至於在函式外的 print,當然都會選擇全域變數來印出,許多初學者會認為 var1 的值已經被改變了,應該會印出 1,其實不是,因為這兩個變數是完全不同的兩個變數。

global 和 nonlocal

閉包

閉包(closure) 是參照了外部環境的函式,什麼意思呢:

def gen_power(base):
    def power(exp):
        return base ** exp
    return power

power2 = gen_power(2)
power3 = gen_power(3)

print(power2(3))
print(power3(2))

我們在 gen_power 函式裡面建立了一個位在函式裡的函式 (區域函式) powerpower 函式本身參照了 base 這個外在變數 (base 既非 power 的參數,也不是 power 的區域變數),所以這種綁定造就了閉包,沒錯,power 函式就是閉包。

閉包有怎麼樣的特性呢?我們發現 power2 = gen_power(2) 會使得 power2 這個變數參照到一個函式,接著使用 power2(3) 的時候會計算 2 的 3 次方,可是明明 power2 我們只提供了 exp 這個參數阿,base 打哪來的呢?別忘了,power 函式綁定了 gen_powerbase 變數,而 base 在當時是被設定為 2,其實講簡單一點,power2 會成為一個計算 2 的次方的函數。

閉包使得原本在函式結束時就會結束作用的 base 變數得到了延續。而 power2(3) 其實就是 gen_power(2)(3),透過 gen_power(2) 得到的函式再利用 3 去呼叫,這種手法又稱為 揉製(curry)

results matching ""

    No results matching ""