預設參數
在程式設計中,一個函式的預設參數是指不必須指定值的參數。在大多數程式設計語言中,函式可以接受一個或多個參數。通常對於每個參數都需要指定它們的值(例如C語言[1])。一些較新的程式設計語言(例如C++)允許程式設計師設定預設參數並指定預設值,當呼叫該函式並未指定值時,該預設參數將為預設值。
C++中的預設參數
考慮如下函式聲明:
int my_func(int a, int b, int c=12);
該函式有三個參數,最後一個參數的預設值為12。程式設計師可以用以下兩種方式呼叫該函式:
result = my_func(1, 2, 3);
result = my_func(1, 2);
第一種呼叫方式中,c的值就像一般函式一樣被設為3。在第二種呼叫方式中,c被省略,而被直接賦值為預設值12。
在函式體中,無法知道參數值是在呼叫時指定的還是直接使用的預設值。
這種定義方法在希望不論是否指定參數時都可以呼叫函式的情況下尤其有用,考慮下面的例子:
void printToScreen(istream &input = cin)
{
// this outputs any input to the screen
cout << input;
}
函式呼叫:
printToScreen();
這個函式呼叫會預設將鍵盤輸入列印到螢幕輸出。通過這種用法列印到螢幕,比起下面的用法是更為合適的:
printToScreen(cin);
另一方面,任何一種輸入流都可以作為參數傳入該函式。此時該函式會將指定輸入流的內容輸出到螢幕,例如:
printToScreen(fileName);
fileName是通過檔案流ifstream打開的可讀檔案。
多載方法
在Java等一些其他語言中,不支援預設參數。但可以用過函式多載(方法多載)的方式來支援不同數量的參數。通過方法多載,讓參數少的方法直接呼叫參數多的方法並指定預設值,就可以達到同樣的效果。例如:
int MyFunc(int a, int b) { return MyFunc(a, b, 12); }
int MyFunc(int a, int b, int c) { /* main implementation here */ }
評價
對於每一次使用預設參數值的函式呼叫,預設的函式值都必須要傳遞一次,相比於函式多載,這造成了代碼臃腫。
如果預設參數不是一個值而是一個表達式,何時計算該表達式則是新的問題。究竟是整個程式執行期間計算一次(語法解釋時、編譯時或執行時)還是每一次呼叫都計算一次。
Python只在模組載入時計算一次預設參數列達式的值。如果我們需要每次呼叫都計算預設值,則可以將預設值設定為監視哨,例如設為None
。隨後在函式第一行,檢查監視哨,如果監視哨是預設值,則計算所需表達式的值。
例如我們可以通過以下方法使函式在每一次使用預設值時都重新取得當前的時間:
import datetime
def f(a, b=None):
b = b or datetime.datetime.now()
作用域和生存周期
一般而言,預設參數就像一個傳入的函式參數或一個在函式開頭定義的局部變數一樣,擁有和局部變數一致的作用域和生存周期。作為一個自動變數會在函式終止時被釋放。
在另外一些情況下,預設參數會被靜態分配。就像靜態變數,如果預設參數的值發生了改變,則在所有函式呼叫中都會發生相應改變。
這種情況在Python中存在。如果預設參數是可變類型(例如列表),則該預設參數就會被靜態分配。為保證預設參數為局部變數,可以使用監視哨之方法實現,就例如:
def f(a, b=None):
b = b or []