函式引數
在 Python 中,定義函式和呼叫函式都很簡單,但如何定義函式引數和傳遞函式引數,則涉及到一些套路了。總的來說,Python 的函式引數主要分為以下幾種:
- 必選引數
- 預設引數
- 可變引數
- 關鍵字引數
必選引數
必選引數可以說是最常見的了,顧名思義,必選引數就是在呼叫函式的時候要傳入數量一致的引數,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
>>> def add(x, y): # x, y 是必選引數 ... print x + y ... >>> add() # 啥都沒傳,不行 Traceback (most recent call last): File "", line 1, in TypeError: add() takes exactly 2 arguments (0 given) >>> add(1) # 只傳了一個,也不行 Traceback (most recent call last): File "", line 1, in TypeError: add() takes exactly 2 arguments (1 given) >>> add(1, 2) # 數量一致,通過 3 |
預設引數
預設引數是指在定義函式的時候提供一些預設值,如果在呼叫函式的時候沒有傳遞該引數,則自動使用預設值,否則使用傳遞時該引數的值。
看看例子就明白了:
1 2 3 4 5 6 7 |
>>> def add(x, y, z=1): # x, y 是必選引數,z 是預設引數,預設值是 1 ... print x + y + z ... >>> add(1, 2, 3) # 1+2+3 6 >>> add(1, 2) # 沒有傳遞 z,自動使用 z=1,即 1+2+1 4 |
可以看到,預設引數使用起來也很簡單,但有兩點需要注意的是:
- 預設引數要放在所有必選引數的後面
- 預設引數應該使用不可變物件
比如,下面對預設引數的使用是錯誤的:
1 2 3 4 5 6 7 8 9 10 11 |
>>> def add(x=1, y, z): # x 是預設引數,必須放在所有必選引數的後面 ... return x + y + z ... File "<stdin>", line 1 SyntaxError: non-default argument follows default argument >>> >>> def add(x, y=1, z): # y 是預設引數,必須放在所有必選引數的後面 ... return x + y + z ... File "<stdin>", line 1 SyntaxError: non-default argument follows default argument |
再來看看為什麼預設引數應該使用不可變物件。
我們看一個例子:
1 2 3 |
>>> def add_to_list(L=[]): ... L.append('END') ... return L |
在上面的函式中,L 是一個預設引數,預設值是 []
,表示空列表。
我們來看看使用:
1 2 3 4 5 6 7 8 9 10 |
>>> add_to_list([1, 2, 3]) # 沒啥問題 [1, 2, 3, 'END'] >>> add_to_list(['a', 'b', 'c']) # 沒啥問題 ['a', 'b', 'c', 'END'] >>> add_to_list() # 沒有傳遞引數,使用預設值,也沒啥問題 ['END'] >>> add_to_list() # 沒有傳遞引數,使用預設值,竟出現兩個 'END' ['END', 'END'] >>> add_to_list() # 糟糕了,三個 'END' ['END', 'END', 'END'] |
為啥呢?我們在呼叫函式的時候沒有傳遞引數,那麼就預設使用 L=[]
,經過處理,L 應該只有一個元素,怎麼會出現呼叫函式兩次,L 就有兩個元素呢?
原來,L 指向了可變物件 []
,當你呼叫函式時,L 的內容發生了改變,預設引數的內容也會跟著變,也就是,當你第一次呼叫時,L 的初始值是 []
,當你第二次呼叫時,L 的初始值是 ['END']
,等等。
所以,為了避免不必要的錯誤,我們應該使用不可變物件作為函式的預設引數。
可變引數
在某些情況下,我們在定義函式的時候,無法預估函式應該制定多少個引數,這時我們就可以使用可變引數了,也就是,函式的引數個數是不確定的。
看看例子:
1 2 3 4 5 6 |
>>> def add(*numbers): ... sum = 0 ... for i in numbers: ... sum += i ... print 'numbers:', numbers ... return sum |
在上面的程式碼中,numbers 就是一個可變引數,引數前面有一個 *
號,表示是可變的。在函式內部,引數 numbers 接收到的是一個 tuple。
在呼叫函式時,我們可以給該函式傳遞任意個引數,包括 0 個引數:
1 2 3 4 5 6 7 8 9 10 11 12 |
>>> add() # 傳遞 0 個引數 numbers: () 0 >>> add(1) # 傳遞 1 個引數 numbers: (1,) 1 >>> add(1, 2) # 傳遞 2 個引數 numbers: (1, 2) 3 >>> add(1, 2, 3) # 傳遞 3 個引數 numbers: (1, 2, 3) 6 |
上面的 *
表示任意引數,實際上,它還有另外一個用法:用來給函式傳遞引數。
看看例子:
1 2 3 4 5 6 7 8 9 10 11 |
>>> def add(x, y, z): # 有 3 個必選引數 ... return x + y + z ... >>> a = [1, 2, 3] >>> add(a[0], a[1], a[2]) # 這樣傳遞引數很累贅 6 >>> add(*a) # 使用 *a,相當於上面的做法 6 >>> b = (4, 5, 6) >>> add(*b) # 對元組一樣適用 15 |
再看一個例子:
1 2 3 4 5 6 7 8 9 10 11 12 |
>>> def add(*numbers): # 函式引數是可變引數 ... sum = 0 ... for i in numbers: ... sum += i ... return sum ... >>> a = [1, 2] >>> add(*a) # 使用 *a 給函式傳遞引數 3 >>> a = [1, 2, 3, 4] >>> add(*a) 10 |
關鍵字引數
可變引數允許你將不定數量的引數傳遞給函式,而關鍵字引數則允許你將不定長度的鍵值對, 作為引數傳遞給一個函式。
讓我們看看例子:
1 2 3 4 5 6 7 8 |
>>> def add(**kwargs): return kwargs >>> add() # 沒有引數,kwargs 為空字典 {} >>> add(x=1) # x=1 => kwargs={'x': 1} {'x': 1} >>> add(x=1, y=2) # x=1, y=2 => kwargs={'y': 2, 'x': 1} {'y': 2, 'x': 1} |
在上面的程式碼中,kwargs 就是一個關鍵字引數,它前面有兩個 *
號。kwargs 可以接收不定長度的鍵值對,在函式內部,它會表示成一個 dict。
和可變引數類似,我們也可以使用 **kwargs
的形式來呼叫函式,比如:
1 2 3 4 5 6 7 8 |
>>> def add(x, y, z): ... return x + y + z ... >>> dict1 = {'z': 3, 'x': 1, 'y': 6} >>> add(dict1['x'], dict1['y'], dict1['z']) # 這樣傳參很累贅 10 >>> add(**dict1) # 使用 **dict1 來傳參,等價於上面的做法 10 |
再看一個例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
>>> def sum(**kwargs): # 函式引數是關鍵字引數 ... sum = 0 ... for k, v in kwargs.items(): ... sum += v ... return sum >>> sum() # 沒有引數 0 >>> dict1 = {'x': 1} >>> sum(**dict1) # 相當於 sum(x=1) 1 >>> dict2 = {'x': 2, 'y': 6} >>> sum(**dict2) # 相當於 sum(x=2, y=6) 8 |
引數組合
在實際的使用中,我們經常會同時用到必選引數、預設引數、可變引數和關鍵字引數或其中的某些。但是,需要注意的是,它們在使用的時候是有順序的,依次是必選引數、預設引數、可變引數和關鍵字引數。
比如,定義一個包含上述四種引數的函式:
1 2 3 4 5 6 |
>>> def func(x, y, z=0, *args, **kwargs): print 'x =', x print 'y =', y print 'z =', z print 'args =', args print 'kwargs =', kwargs |
在呼叫函式的時候,Python 會自動按照引數位置和引數名把對應的引數傳進去。讓我們看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
>>> func(1, 2) # 至少提供兩個引數,因為 x, y 是必選引數 x = 1 y = 2 z = 0 args = () kwargs = {} >>> func(1, 2, 3) # x=1, y=2, z=3 x = 1 y = 2 z = 3 args = () kwargs = {} >>> func(1, 2, 3, 4, 5, 6) # x=1, y=2, z=3, args=(4, 5, 6), kwargs={} x = 1 y = 2 z = 3 args = (4, 5, 6) kwargs = {} >>> func(1, 2, 4, u=6, v=7) # args = (), kwargs = {'u': 6, 'v': 7} x = 1 y = 2 z = 4 args = () kwargs = {'u': 6, 'v': 7} >>> func(1, 2, 3, 4, 5, u=6, v=7) # args = (4, 5), kwargs = {'u': 6, 'v': 7} x = 1 y = 2 z = 3 args = (4, 5) kwargs = {'u': 6, 'v': 7} |
我們還可以通過下面的形式來傳遞引數:
1 2 3 4 5 6 7 8 |
>>> a = (1, 2, 3) >>> b = {'u': 6, 'v': 7} >>> func(*a, **b) x = 1 y = 2 z = 3 args = () kwargs = {'u': 6, 'v': 7} |
小結
- 預設引數要放在所有必選引數的後面。
- 應該使用不可變物件作為函式的預設引數。
*args
表示可變引數,**kwargs
表示關鍵字引數。- 引數組合在使用的時候是有順序的,依次是必選引數、預設引數、可變引數和關鍵字引數。
*args
和**kwargs
是 Python 的慣用寫法。