Python基礎之定義有預設引數的函式
1. 構建有預設引數的函式
當我們在構建一個函式或者方法時,如果想使函式中的一個或者多個引數使可選的,並且有一個預設值,那麼可以在函式定義中給引數指定一個預設值,並且放到引數列表的最後就行了。比如:
def func(a, b=42): print(a, b) func(1) #a=1, b=42 func(1,2) #a=1, b=2
如果預設引數使一個可以修改的容器,比如一個列表,集合或者字典,可以使用None作為預設值。比如:
#使用列表list作為預設值 def func(a, b=None): if b is None: b = [] ···
但是,如果你並不是想提供一個預設值,而僅僅知識想測試下某個預設引數是不是有值傳遞進來,可以這樣寫:
_no_value = object() def func(a, b=_no_value): if b is _no_value: print("b沒有值") else: print(a, b) func(1) # b沒有值 func(1, None) # 1 None
仔細通過測試可以發現,傳遞一個None值和不傳值兩種情況是有差別的。
2. 引數陷阱
2.1 預設引數的值
預設引數的值僅僅在函式定義的時候賦值一次,示例程式碼如下:
x = 42 def func(a, b=x): print(a, b) func(1) #1 42 x = 23 func(1) #1 42
從上面例子中可以看出,當我們改變x的值的對預設引數值並沒有影響,這是因為在函式定定義的時候就已經確定了它的預設值了。
2.2 預設引數值的型別
預設引數值的型別應該是不可變物件,比如None,True,False,數字或字串,而不能使用列表,字典等可變型別。
不要像下面這樣寫程式碼:
def func(a, b=[]): #不能這麼寫 ···
如果這樣寫了,當預設值在某些地方被修改之後,程式就會出現問題。
這些被修改的程式會影響到下次呼叫這個引數時的預設值。比如:
def func(a, b=[]): return b x = func(1) print(x) #[] x.append("a") x.append("b") print(x) #['a', 'b'] y = func(1) print(y) #['a', 'b']
可以看到,b的預設值從一個空list,變成了[“a”, “b”],這種不會是你想要的預設引數。
為了避免這種情況的發生,最好是將預設值設定為None,然後在函式裡面檢查它。
但是在將預設值設定為None之後,測試None值時使用is操作符是很重要的,is是這種方法的關鍵點。
有人可能會這樣寫:
def func(a, b=None): if not b: b = [] ···
這麼寫有有一個問題,就是雖然None確實會被當成False,但是還有其他的物件(比如長度為0的字串,列表,元組,字典等)都會被當作False。因此上面的程式碼會誤將一些其他輸入也會當作沒有輸入。比如:
def func(a, b=None): if not b: b = [] return b print(func(1)) # [] print(func(1, [])) # [] print(func(1, 0)) # [] print(func(1, "")) # []
從結果中就可以看到,b的值並沒有發生改變,這不是我們想要的結果。
2.3 測試某個可選引數
當一個函式需要測試某個可選引數是否被使用者傳遞進來。這個時候需要小心的是不能用某個預設值,比如None,0或者False值來測試使用者提供的值(因為這些值都是合法的值,是可能被使用者傳遞進來的)。
你可以建立一個獨一 無二的私有物件例項,就像上面的_no_value變數一樣。在函式裡面,你可以通過檢查被傳遞引數值跟這個例項是否一樣來判斷。
這裡的思路就是使用者不可能去傳遞這個_no_value例項作為輸出。因此這裡通過檢查這個值就能確定某個引數是否被傳遞進來了。