變數範圍
全域變數與區域變數
提到函式,便不得不談到變數的有效範圍,也就是變數被認定(認識)的範圍。
- 定義在函式外的變數其範圍是一整個 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
函式裡面建立了一個位在函式裡的函式 (區域函式) power
, power
函式本身參照了 base
這個外在變數 (base
既非 power
的參數,也不是 power
的區域變數),所以這種綁定造就了閉包,沒錯,power
函式就是閉包。
閉包有怎麼樣的特性呢?我們發現 power2 = gen_power(2)
會使得 power2
這個變數參照到一個函式,接著使用 power2(3)
的時候會計算 2 的 3 次方,可是明明 power2
我們只提供了 exp
這個參數阿,base
打哪來的呢?別忘了,power
函式綁定了 gen_power
的 base
變數,而 base
在當時是被設定為 2,其實講簡單一點,power2
會成為一個計算 2 的次方的函數。
閉包使得原本在函式結束時就會結束作用的 base
變數得到了延續。而 power2(3)
其實就是 gen_power(2)(3)
,透過 gen_power(2)
得到的函式再利用 3 去呼叫,這種手法又稱為 揉製(curry)。