讀古今文學網 > 父與子的編程之旅:與小卡特一起學Python > 13.6 變量作用域 >

13.6 變量作用域

你可能已經注意到,有些變量在函數之外,如 totalPrice,還有一些變量在函數內部,如 total。這些變量只是同一個東西的兩個不同名字。這就像第2章中所說的 YourTeacher = MyTeacher

在我們的 calculateTax 例子中,totalPricetotal 是貼在同一個東西上的兩個標籤。對於函數而言,函數內的名字只是在函數運行時才會創建。在函數運行之前或者完成運行之後甚至根本不存在。Python 提供了內存管理(memory management),可以自動完成這個工作。Python 在函數運行時會創建新的名字在函數內使用,當函數完成時會把它們刪除。最後這部分很重要:函數運行結束時,其中的所有名字都不再存在。

函數運行時,函數之外的名字被擱置一邊,而沒有用到。只有函數內部的名字會被用到。程序中使用(或者可以使用)變量的部分稱為這個變量的作用域(scope)。

局部變量

在代碼清單 13-4 中,變量 pricetotal 只在函數內使用。我們說 pricetotaltax_rate 的作用域是 calculateTax 函數。這也稱為這些變量是局部的(local)。pricetotaltax_rate 變量是 calculateTax 函數中的局部變量。

要瞭解這是什麼意思,一種方法是向代碼清單 13-4 中的程序增加一行代碼,嘗試在函數之外的某個位置打印 price 的值。代碼清單 13-5 做了這個嘗試。

代碼清單 13-5 嘗試打印一個局部變量

如果運行這個程序,會得到這樣一個錯誤:

錯誤消息的最後一行解釋了這個問題的原委:在 calculateTax 函數以外,變量 price 根本沒有定義。它只是在函數運行時才存在。試圖在這個函數之外打印 price 的值時(此時函數並沒有運行),就會得到一個錯誤。

全局變量

與局部變量 price 對應,代碼清單 13-5 中的變量 my_pricetotalPrice 在函數之外定義(程序主部分中)。我們使用全局變量(global)表示有更大作用域的變量。在這種情況下,更大是指程序的主部分,而不是函數內部。如果擴展代碼清單 13-5 中的程序,完全可以在另一個位置使用變量 my_pricetotalPrice,它們仍然有之前給定的值。它們仍在合法的作用域中(in scope)。因為我們可以在程序的任何地方使用這些變量,所以把它們稱作全局變量(global variable)。

在代碼清單 13-5 中,試圖在函數之外打印一個函數內的變量時,會得到一條錯誤消息。這個變量不存在,也就是說它在作用域之外(out of scope)。如果反過來:從函數內打印一個全局變量,你認為會發生什麼?

代碼清單 13-6 試圖從 calculateTax 函數中打印變量 my_price。試試看會發生什麼。

代碼清單 13-6 在函數中使用全局變量

可以嗎?真的可以!不過為什麼呢?

開始討論變量作用域時,我曾經說過,Python 利用內存管理在函數運行時自動創建局部變量。內存管理還會做其他事情。如果在函數中使用主程序中定義的變量名,Python 允許你使用這個全局變量,只要你不要試圖改變它。

所以你可以這樣做:

print my_price  

或者這樣做:

your_price = my_price  

因為它們都不會改變 my_price

如果函數的任何部分試圖改變這個變量,Python 會創建一個新的局部變量。所以如果你打算這樣做:

my_price = my_price + 10  

那麼 my_price 將是 Python 在函數運行時創建的一個新的局部變量。

在代碼清單 13-6 的例子中,打印出的值是全局變量 my_price,因為函數沒有改變這個變量。代碼清單 13-7 中的程序表明,如果確實試圖在函數內部改變全局變量,你會得到一個新的局部變量。試著運行這個程序,看看會有什麼結果。

代碼清單 13-7 嘗試在函數內部修改一個全局變量

如果運行代碼清單 13-7 中的代碼,會有下面的輸出:

可以看到,現在有兩個名為 my_price 的不同變量,分別有不同的值。一個是 calculateTax 函數中的局部變量,我們將它設置為 10 000。另一個是主程序中定義的全局變量,用來獲取用戶的輸入,它的值是 7.99。