在Python/ target=_blank class=infotextkey>Python的代碼中經(jīng)常會(huì)見(jiàn)到這兩個(gè)詞 args 和 kwargs,前面通常還會(huì)加上一個(gè)或者兩個(gè)星號(hào)。
- args 是 arguments 的縮寫(xiě),表示位置參數(shù)
- kwargs 是 keyword arguments 的縮寫(xiě),表示關(guān)鍵字參數(shù)
注:這其實(shí)就是 Python 中可變參數(shù)的兩種形式,并且 *args 必須放在 **kwargs 的前面,因?yàn)槲恢脜?shù)在關(guān)鍵字參數(shù)的前面。
我們將通過(guò)以下5方面來(lái)理解:
- *的作用
- *args的用法
- **的作用
- **kwargs的用法
- 實(shí)例
*的作用
通過(guò)一個(gè)函數(shù)調(diào)用來(lái)理解“*”的作用
#定義一個(gè)含三位置參數(shù)的函數(shù)
>>>def fun(a, b, c):
... print a,b,c#傳三個(gè)位置參數(shù),調(diào)用此函數(shù)>>> fun(1,2,3)
1 2 3 # 輸出
現(xiàn)在我們定義一個(gè)含三個(gè)整數(shù)的數(shù)列,并使用‘*’
>>> var = [1, 2, 3]
>>> fun(*var)
1 2 3 # 輸出
'*'做了什么?它拆開(kāi)數(shù)列'var'的數(shù)值作為位置參數(shù),并把這些位置參數(shù)傳給函數(shù)‘fun’來(lái)調(diào)用。
這意味著fun(*var)與fun(1,2,3)是等效的,因?yàn)関ar=[1,2,3]
注:*var與位置參數(shù)可混合使用
*args的用法
"*args"在函數(shù)定義中是做什么用的?它接收元組作為位置參數(shù),而非是常見(jiàn)的參數(shù)列表。在這里,“args”是個(gè)元組。
“args”與“常規(guī)參數(shù)列表”混合使用
#在函數(shù)定義中,參數(shù)‘a’代表‘常規(guī)參數(shù)列表’
>>> def fun(a, *args):
... print("a is ", a)
... print("args is ", args)
#‘args’接收除常規(guī)參數(shù)之外的位置參數(shù)作為元組>>> fun(11, 12, 13, 14)
a is 11
args is (12, 13, 14)
注:'args'既然是元組,我們就可以遍歷它。
**的作用
通過(guò)一個(gè)函數(shù)調(diào)用來(lái)理解“**”的作用
# 定義一個(gè)三參數(shù)的函數(shù)
>>> def fun(a, b, c):
... print(a, b, c)...>>> func(1, 2, 3)
1 2 3
>>> fun(a=1, b=2, c=3)
1 2 3
使用“**”調(diào)用函數(shù),這種方式我們需要一個(gè)字典。
>>> var = {'b' : 2, 'c' : 3}
>>> fun(1, **var)
1 2 3
注:在函數(shù)調(diào)用中使用‘*’,我們需要元組;在函數(shù)調(diào)用中使用‘**’,我們需要一個(gè)字典
“**”做了什么?它unpack字典,并將字典中的數(shù)據(jù)項(xiàng)作為鍵值參數(shù)傳給函數(shù)。因此,fun(1, **var)的寫(xiě)法與fun(1, b=2, c=3)等效。
**kwargs的用法
在函數(shù)定義中“**kwargs”意味著什么?kwargs接收除常規(guī)參數(shù)列表外的鍵值參數(shù)字典,在這里'kwargs'是個(gè)字典。
重新定義函數(shù):
>>> def fun(a, **kwargs):
... print("a is ", a)
... print("We expect kwargs 'b' and 'c' in this function")
... print("b is ", kwargs['b'])
... print("c is ", kwargs['c'])
...>>> fun(1, b=3, c=5)
a is 1
We expect kwargs 'b' and 'c' in this function
b is 3
c is 5
注:在一個(gè)字典前使用“**”可以u(píng)npack字典,傳字典中的數(shù)據(jù)項(xiàng)作為鍵值參數(shù)。
實(shí)例
通過(guò)一個(gè)應(yīng)用實(shí)例來(lái)說(shuō)明'args','kwargs'應(yīng)用場(chǎng)景以及為何要使用它。
在繼承類和重寫(xiě)方法的時(shí)候,我們可以用到’*args’和’**kwargs’將接收到的位置參數(shù)和鍵值參數(shù)給父類方法,通過(guò)實(shí)例我們更好的理解。
>>> class Model(object):
... def __init__(self, name):
... self.name = name... def save(self, force_update=False, force_insert=False):
... if force_update and force_insert:
... raise ValueError("Cannot perform both operations")
... if force_update:
... print("Updated an existing record")
... if force_insert:
... print("Created a new record")
構(gòu)造一個(gè)新類,類有’Model’的行為,但我們只有檢查一些條件后才會(huì)保存這個(gè)類的對(duì)象。這個(gè)新類繼承’Model’,重寫(xiě)’Model’的’save()’
>>> class ChildModel(Model):
... def save(self, *args, **kwargs):
... if self.name=='abcd':
... super(ChildModel, self).save(*args, **kwargs)... else:
... return None
實(shí)際上對(duì)應(yīng)的保存動(dòng)作發(fā)生在’Model’的’save’方法中。所以我們調(diào)用子類的的’save()’方法而非’Model’的方法.子類ChildModel的’save()’接收任何父類save()需要的參數(shù),并傳給父類方法。因此,子類’save()’方法參數(shù)列表中有”*args”和”**kwargs”,它們可以接收任意位置參數(shù)或鍵值參數(shù),常規(guī)參數(shù)列表除外。
下面創(chuàng)建ChildModel實(shí)體并保存:
>>> c=ChildModel('abcd')
>>> c.save(force_insert=True)
Created a new record
>>> c.save(force_update=True)
Updated an existing record
這里傳鍵值參數(shù)給對(duì)象的save()方法,調(diào)用的是子類的save()。