引數匹配模型——Python學習之引數(二)

ARM的程式設計師敲著詩歌的夢發表於2020-04-04

引數匹配模型——Python學習之引數(二)

位置引數:從左至右進行匹配

一般情況下,也是我們最常使用的那種方法,通過位置進行匹配,把引數值傳遞給引數頭部的引數名稱,匹配順序從左到右。

例如:

def func(name, father_name):
    print("%s's father is %s"%(name, father_name))

func('Xiaowang', 'Laowang')
func('Laowang', 'Xiaowang')

執行結果是:

Xiaowang's father is Laowang
Laowang's father is Xiaowang

關鍵字引數:通過引數名進行匹配

呼叫者可以定義哪一個引數接受這個值,通過在呼叫時使用引數的變數名,即 name=value這種語法。

例如:

def func(name, father_name):
    print("%s's father is %s"%(name, father_name))

func(name='Xiaowang', father_name='Laowang')
func(father_name='Laowang', name='Xiaowang')

執行結果是:

Xiaowang's father is Laowang
Xiaowang's father is Laowang

預設引數:為沒有傳入值的引數定義引數值

如果呼叫時傳入的值過於少的話,函式能夠為引數指定預設值,這裡再次使用語法 name=value.

例如:

def func(name, age=10):
    print("%s's age is %d"%(name, age))

func('Wang', 20)
func('Wang')  # age使用預設值10

執行結果是:

Wang's age is 20
Wang's age is 10

可變引數:收集任意多於基於位置或關鍵字的引數

如果引數名稱以字元*開頭,則表示收集任意多的額外引數(這個特性常常叫做可變引數)。

例如:

def print_params(*params):  
	print(params) 

這裡好像只指定了一個引數,但它前面有一個星號。這是什麼意思呢?嘗試使用一個引數來呼叫這個函式,看看結果如何。

>>> print_params('Testing') 
>>> ('Testing',) 

注意到列印的是一個元組,因為裡面有一個逗號。也就是說前面有星號的引數將被放在元組中?我們們再試試。

>>> print_params(1, 2, 3) 
(1, 2, 3) 

可見,引數前面的星號將提供的所有值都放在一個元組中,也就是將這些值收集起來。

再看一個例子:

def print_params_2(title, *params):  
    print(title) 
    print(params) 

>>> print_params_2('Params:', 1, 2, 3) 
Params: 
(1, 2, 3) 

因此星號意味著收集餘下的位置引數。如果沒有可供收集的引數,params將是一個空元組。

>>> print_params_2('Nothing:') 
Nothing: 
() 

帶星號的引數也可放在其他位置(而不是最後),但不同的是,在這種情況下你需要做些額外的工作:使用名稱來指定後續引數。

>>> def in_the_middle(x, *y, z): 
...     print(x, y, z) 
... 
>>> in_the_middle(1, 2, 3, 4, 5, z=7) 
1 (2, 3, 4, 5) 7 
>>> in_the_middle(1, 2, 3, 4, 5, 7) 
Traceback (most recent call last):  
  File "<stdin>", line 1, in <module> 
TypeError: in_the_middle() missing 1 required keyword-only argument: 'z' 

第9行的keyword-only argument後文會講。

星號不會收集關鍵字引數。

def print_params_2(title, *params):  
    print(title) 
    print(params) 

>>> print_params_2('Hmm...', something=42) 
>>> Traceback (most recent call last):  
>>>   File "<stdin>", line 1, in <module> 
>>> TypeError: print_params_2() got an unexpected keyword argument 'something' 

要收集關鍵字引數,可使用兩個星號。

>>> def print_params_3(**params): 
...     print(params) 
... 
>>> print_params_3(x=1, y=2, z=3) 
{'z': 3, 'x': 1, 'y': 2} 

如你所見,這樣得到的是一個字典而不是元組。

可變引數解包:傳遞任意多的基於位置或關鍵字的引數

呼叫者能夠再使用*語法將引數集合打散,分成引數。這個*與在函式頭部的*恰恰相反:在函式頭部它意味著收集任意多的引數,而在呼叫者中意味著引數解包。

例如,我們能夠通過一個元組給一個函式傳遞4個引數。

>>> def func(a, b, c, d):
...     print(a, b, c, d)
... 
>>> args = (1, 2, 3, 4)
>>> func(*args)
1 2 3 4

類似地,如果在呼叫函式時,**會以鍵值對的形式解包一個字典,使其成為關鍵字引數。

>>> def func(a, b, c, d):
...     print(a, b, c, d)
... 
>>> args = {'a':2, 'b':4, 'c':6, 'd':8}
>>> func(**args)
2 4 6 8

提示

不要混淆函式頭部或函式呼叫時*或者**的語法:在函式頭部它意味著收集任意數量的引數,在函式呼叫時,它解包任意數量的引數。

Keyword-only引數:引數必須按照名稱傳遞

Python3.0 把函式頭部的排序規則通用化了,允許我們指定 keyword-only 引數,即必須只按照關鍵字傳遞並且不會由一個位置引數來填充的引數。

從語法上講, keyword-only 引數編碼為命名的引數,出現在引數列表中的 *args 之後,所有這些引數都必須在呼叫中使用關鍵字語法來傳遞。例如,在下面的程式碼中, a 可能按照名稱或者位置來傳遞,b 收集任何額外的位置引數,並且 c 必須只按照關鍵字傳遞:

>>> def kwonly(a, *b, c):
        print(a, b, c)
>>> kwonly(1, 2, c=3)
1 (2,) 3
>>> kwonly(a=1, c=3)
1 () 3
>>> kwonly(1, 2, 3)
TypeError: kwonly() missing 1 required keyword-only argument: 'c'

我們也可以在引數列表中使用一個*字元,來表示一個函式期待跟在*後面的所有引數都作為關鍵字引數傳遞。在下面的例子中,a 可能按照位置或者名稱傳遞,但是 b 和 c 必須按照關鍵字傳遞。

>>> def kwonly(a, *, b, c):
        print(a, b, c)
>>> kwonly(1, c=3, b=2)
1 2 3
>>> kwonly(c=3, b=2, a=1)
1 2 3
>>> kwonly(1, 2, 3)
TypeError: kwonly() takes 1 positional argument but 3 were given
>>> kwonly(1)
TypeError: kwonly() missing 2 required keyword-only arguments: 'b' and 'c'

仍然可以對 keyword-only 引數使用預設值,即便它們出現在函式頭部中的*後面。在下面的例子中,a 可能按照名稱或位置傳遞,而 b 和 c 是可選的,但是如果使用的話必須按照關鍵字傳遞。

>>> def kwonly(a, *, b='spam', c='ham'):
        print(a, b, c)
>>> kwonly(1)
1 spam ham
>>> kwonly(1, c=3)
1 spam 3
>>> kwonly(a=1)
1 spam ham
>>> kwonly(c=3, b=2, a=1)
1 2 3
>>> kwonly(1, 2)
TypeError: kwonly() takes 1 positional argument but 2 were given

實際上,帶有預設值的 keyword-only 引數是可選的,但是,那些沒有預設值的 keyword-only 引數真正地變成了函式必須的 keyword-only 引數。我們們再看幾個例子:

>>> def kwonly(a, *, b, c='spam'):
        print(a, b, c)
>>> kwonly(1, b='eggs')
1 eggs spam
>>> kwonly(1, c='eggs')
TypeError: kwonly() missing 1 required keyword-only argument: 'b'
>>> kwonly(1, 2)
TypeError: kwonly() takes 1 positional argument but 2 were given
>>> def kwonly(a, *, b=1, c, d=2):
        print(a, b, c, d)
>>> kwonly(3, c=4)
3 1 4 2
>>> kwonly(3, c=4, b=5)
3 5 4 2
>>> kwonly(3)
TypeError: kwonly() missing 1 required keyword-only argument: 'c'
>>> kwonly(1, 2, 3)
TypeError: kwonly() takes 1 positional argument but 3 were given

相關文章:Python學習之引數(一)

參考資料

《Learning Python,5th Edition》

《Python基礎教程》人民郵電出版社,第3版

相關文章