深入理解python的 *args 和**kwargs 可變參數(shù)

上篇文章已經(jīng)詳細(xì)的介紹了python函數(shù)的傳參方式轧拄,本文接著上文的內(nèi)容詳細(xì)的講解一下可變參數(shù) *args **kwargs慕购,

  • 本文主要內(nèi)容:
  1. 可變參數(shù)的定義
  2. 理解參數(shù)傳遞(*)星號(hào)
  3. *args 非鍵值可變參數(shù)的定義
  4. 理解參數(shù)傳遞(**)雙星號(hào)
  5. **kwargs 鍵值可變參數(shù)的定義
  6. 可變參數(shù)的混合調(diào)用和定義

1.可變參數(shù)定義

定義函數(shù)時(shí)鲫尊,有時(shí)候我們不確定調(diào)用的時(shí)候會(huì)多少個(gè)參數(shù),就可以使用可變參數(shù)

def func(required_arg, default_arg=None, *args, **kwargs):
    pass
    #  required_arg 必傳位置參數(shù)
    #  default_arg 默認(rèn)參數(shù)
    # *args 非鍵值可變參數(shù)
    # **kwargs 鍵值可變參數(shù)

上面是Python得一個(gè)典型的函數(shù)定義,簡單明了的表述了python的四種參數(shù)定義方式

  • required_arg 必傳位置參數(shù)
  • default_arg 默認(rèn)參數(shù)
  • *args 非鍵值可變參數(shù)
  • **kwargs 鍵值可變參數(shù)

注意:這幾種參數(shù)是有順序的傅是,位置參數(shù) > 默認(rèn)參數(shù)>非鍵值可變參數(shù)>鍵值可變參數(shù)

今天主要介紹可變參數(shù):
Python有一個(gè)特殊的語法,(單星號(hào))(雙星號(hào)),允許您將數(shù)量可變的參數(shù)傳遞給函數(shù)沮尿。 約定俗成的方式通常寫args和kwargs, args和kwargs 只是變量名,你可以寫vars和*vars實(shí)現(xiàn)相同的結(jié)果空凸。

*args是用來傳遞一個(gè)非鍵值變長參數(shù)列表功能嚎花。
**kwargs通常用來傳遞關(guān)鍵字變長參數(shù)。

2. 理解參數(shù)傳遞(*)星號(hào)

>>> def add(x, y):
...     print("x:",x)
...     print("y:",y)
...     print("sum:", x+y)

上面定義一個(gè)簡單的函數(shù)add劫恒,我們通常的調(diào)用方式

>>> add(1, 2)
x: 1
y: 2
sum: 3
>>> add(x=1, y=2)
x: 1
y: 2
sum: 3

當(dāng)面我們多傳或者少傳參數(shù)程序就會(huì)拋出異常

>>> add(1)
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  TypeError: add() missing 1 required positional argument: 'y'
>>> add(1,2,3)
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  TypeError: add() takes 2 positional arguments but 3 were given

如果我們想通過1個(gè)變量傳入多個(gè)參數(shù)怎么傳贩幻?

>>> nums = (1,2)
>>> add(nums)
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  TypeError: add() missing 1 required positional argument: 'y'

我們把參數(shù)值封裝到一個(gè)tuple 中轿腺,然后直接傳遞到add 中程序拋出了異常參數(shù)缺失,那要如何傳參丛楚,可以使用*號(hào)

>>> nums = (1,2)
>>> add(*nums)
x: 1
y: 2
sum: 3

>>> nums = (1,2,3)
>>> add(*nums)
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  TypeError: add() takes 2 positional arguments but 3 were given

通過上面執(zhí)行結(jié)果可以做到族壳,只要在nums前加上,并且nums 的數(shù)量跟參數(shù)一致就可以調(diào)用成功,這是什么原因趣些?
這里有一個(gè)知識(shí)點(diǎn)叫做序列化解包仿荆,在傳遞元組時(shí),讓元組的每一個(gè)元素對(duì)應(yīng)一個(gè)位置參數(shù)坏平,當(dāng)
nums 傳遞到函數(shù)里面時(shí)拢操,程序會(huì)自動(dòng)解包映射到位置參數(shù)上

3. *args 非鍵值可變參數(shù)的定義

我們?cè)诙x函數(shù)時(shí),發(fā)現(xiàn)不能確認(rèn)非鍵值參數(shù)的個(gè)數(shù)的時(shí)候舶替,我們就可以定義為可變非鍵值參數(shù)

def add(*args): 
...     sum = 0
...     for arg in args: #args是個(gè)元組
...             print(arg)
...             sum += arg
...     print("sum:", sum)

我們通過*args 代表接收一個(gè)可變參數(shù)列表令境,那如何調(diào)用可變參數(shù)列表的函數(shù)呢

>>> add() #不傳參數(shù)
sum: 0
>>> add(1,2,3)#通過位置參數(shù)傳遞
1
2
3
sum: 6
>>> nums = (1,2,3)#通過元祖或者列表 加* 傳遞
>>> add(*nums)
1
2
3
sum: 6

從上面的調(diào)用方式
args 定義的函數(shù),可以傳0個(gè)或者-個(gè)以上參數(shù)顾瞪,可以通過位置參數(shù)傳遞舔庶,也可以傳遞

位置參數(shù)和可變參數(shù)*args 的解包關(guān)系

def add(num, *args): 
...     print("num:", num)
...     sum = 0
...     for arg in args: #args是個(gè)元組
...             print(arg)
...             sum += arg
...     print("sum:", sum)

當(dāng)我們不傳參數(shù)的時(shí)候,程序會(huì)報(bào)錯(cuò)陈醒,因?yàn)榈谝粋€(gè)是必傳位置參數(shù)惕橙,所以不傳會(huì)拋出異常

>>> add()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: add() missing 1 required positional argument: 'num'

當(dāng)我們傳遞一個(gè)參數(shù)的時(shí)候,程序正常執(zhí)行钉跷,num 獲取到傳入的參數(shù)值弥鹦,args 沒有取到值

>>> add(1)
num: 1
sum: 0

當(dāng)我們傳遞二個(gè)參數(shù)的時(shí)候,程序正常執(zhí)行爷辙,num 獲取到第一個(gè)參數(shù)值彬坏,args 取到第二參數(shù)

>>> add(1, 2)
num: 1
2
sum: 2

當(dāng)我們傳遞三個(gè)參數(shù)的時(shí)候,程序正常執(zhí)行犬钢,num 獲取到第一個(gè)參數(shù)值苍鲜,args 取到第一個(gè)以后參數(shù)

>>> add(1, 2, 3)
num: 1
2
3
sum: 5

當(dāng)我們傳遞一個(gè)元祖的時(shí)候,程序正常執(zhí)行玷犹,num 獲取到第一個(gè)參數(shù)值,args 取到第一個(gè)以后參數(shù)

>>> nums = (1,2,3)
>>> add(*nums)
num: 1
2
3
sum: 5

由上可知洒疚,在使用args 定義函數(shù)時(shí)候歹颓,如果可變參數(shù)(args)之前有位置參數(shù),解包參數(shù)會(huì)優(yōu)先賦值給位置參數(shù)油湖,剩余的變量賦值給可變參數(shù)

理解參數(shù)傳遞(**)雙星號(hào)

>>> def fun(x, y, z):
...     print("x:", x)
...     print("y:", y)
...     print("z:", z)
... 
>>> fun(1,2,3)
x: 1
y: 2
z: 3
>>> fun(x=1,y=2,z=3)
x: 1
y: 2
z: 3
>>> fun(1,y=2,z=3)
x: 1
y: 2
z: 3

調(diào)用函數(shù)func 我們可以通過以上方式傳參巍扛,我們還能有其他方式嗎?有乏德,那就是通過**

>>> nums = {"x":1,"y":2, "z":3}
>>> fun(**nums)
x: 1
y: 2
z: 3
>>> nums = {"y":2, "z":3}
>>> fun(1, **nums)
x: 1
y: 2
z: 3

我們可以把參數(shù)封裝成字典撤奸,然后通過**nums 的方式傳給函數(shù)func吠昭,實(shí)現(xiàn)原理是啥?
* 是解包賦值給位置參數(shù)
** 是解包賦值給關(guān)鍵詞參數(shù)(關(guān)鍵詞參數(shù)參考前文)

**kwargs 鍵值可變參數(shù)的定義

用”**kwargs”定義函數(shù),kwargs接收除常規(guī)參數(shù)列表以外的鍵值參數(shù)字典
如果我們需要傳遞鍵值可變參數(shù)就如下定義函數(shù)

def func(**kwargs):
>>> def func(**kwargs):
...     for key, value in kwargs.items(): #kwargs 是一個(gè)字典
...             print("key:", key, " value:", value)
... 

我們通過**kwargs代表接收一個(gè)可變參數(shù)字典胧瓜,那如何調(diào)用可變參數(shù)字典的函數(shù)呢

>>> func(a=1,b=2)
key: a  value: 1
key: b  value: 2
>>> nums = {"a": 1, "b": 2}
>>> func(**nums)
key: a  value: 1
key: b  value: 2

從上面的調(diào)用方式
**kwargs 定義的函數(shù)矢棚,可以通過關(guān)鍵詞參數(shù)傳遞,也可以**字典傳遞

6. 可變參數(shù)的混合調(diào)用和定義

位置參數(shù)府喳、默認(rèn)參數(shù)蒲肋、可變參數(shù)的混合使用,基本原則是:先位置參數(shù)钝满,默認(rèn)參數(shù)兜粘, 非鍵值可變參數(shù)(args),鍵值可變參數(shù)(kwargs)

def func(required_arg, default_arg=None, *args, **kwargs):
    pass
    #  required_arg 必傳位置參數(shù)
    #  default_arg 默認(rèn)參數(shù)
    # *args 非鍵值可變參數(shù)
    # **kwargs 鍵值可變參數(shù)

args和*kwargs 的區(qū)別

>>> def func(*args, **kwargs):
...     print("args:", args)
...     print("kwargs", kwargs)
... 
>>> func(1,2)
args: (1, 2)
kwargs {}
>>> func(a=1, b=2)
args: ()
kwargs {'a': 1, 'b': 2}
>>> func(1,2,a=1, b=2)
args: (1, 2)
kwargs {'a': 1, 'b': 2}

可以看到弯蚜,*args 表示任何多個(gè)非鍵值參數(shù)孔轴,它是一個(gè)tuple;**kwargs 表示關(guān)鍵字參數(shù)碎捺,它是一個(gè)dict路鹰。并且同時(shí)使用*args**kwargs時(shí),必須*args參數(shù)列要在**kwargs前牵寺,像func(a=1, b='2',1,2 )這樣調(diào)用的話悍引,會(huì)提示語法錯(cuò)誤“SyntaxError: non-keyword arg after keyword arg”

*args與位置參數(shù)和默認(rèn)參數(shù)混用

args與位置參數(shù)和默認(rèn)參數(shù)混用:args要放到位置參數(shù)后

def func(a, *args, b=1):
...     print("a:", a)
...     print("b:", b)
...     print("args:", args)
... 

**kwargs與位置參數(shù)和默認(rèn)參數(shù)混用

**kwargs 要放在默認(rèn)參數(shù)之后

正確定義
def func(a,  b=1,**kwargs):
...     print("a:", a)
...     print("b:", b)
...     print("args:", args)
... 
錯(cuò)誤定義
def func(a, **kwargs, b=1):
...     print("a:", a)
...     print("b:", b)
...     print("args:", args)
... 
SyntaxError: invalid syntax

總結(jié)

了解函數(shù)4種參數(shù)傳遞方式帽氓,位置參數(shù)趣斤,關(guān)鍵詞參數(shù),默認(rèn)參數(shù)黎休,可變參數(shù)
理解*(單星號(hào))浓领,**(雙星號(hào))的傳參方式
* args和** kwargs是特殊關(guān)鍵字函數(shù)可以將可變長度參數(shù)。
* args通過數(shù)量可變的non-keyworded參數(shù)列表和列表的操作可以執(zhí)行势腮。
* * kwargs通過變量數(shù)量的關(guān)鍵字參數(shù)字典功能字典可以執(zhí)行的操作联贩。
注意:不同的類型的參數(shù)定義和傳遞都是有順序要求的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市捎拯,隨后出現(xiàn)的幾起案子泪幌,更是在濱河造成了極大的恐慌,老刑警劉巖署照,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件祸泪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡建芙,警方通過查閱死者的電腦和手機(jī)没隘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來禁荸,“玉大人右蒲,你說我怎么就攤上這事阀湿。” “怎么了瑰妄?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵陷嘴,是天一觀的道長。 經(jīng)常有香客問我翰撑,道長罩旋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任眶诈,我火速辦了婚禮涨醋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘逝撬。我一直安慰自己浴骂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布宪潮。 她就那樣靜靜地躺著溯警,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狡相。 梳的紋絲不亂的頭發(fā)上梯轻,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音尽棕,去河邊找鬼喳挑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛滔悉,可吹牛的內(nèi)容都是我干的伊诵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼回官,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼曹宴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起歉提,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤笛坦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后苔巨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弯屈,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年恋拷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厅缺。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蔬顾,死狀恐怖宴偿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诀豁,我是刑警寧澤窄刘,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站舷胜,受9級(jí)特大地震影響娩践,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜烹骨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一翻伺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沮焕,春花似錦吨岭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至魁巩,卻和暖如春急灭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背谷遂。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國打工葬馋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人埋凯。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓点楼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親白对。 傳聞我的和親對(duì)象是個(gè)殘疾皇子掠廓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 〇、前言 本文共108張圖甩恼,流量黨請(qǐng)慎重蟀瞧! 歷時(shí)1個(gè)半月,我把自己學(xué)習(xí)Python基礎(chǔ)知識(shí)的框架詳細(xì)梳理了一遍条摸。 ...
    Raxxie閱讀 18,954評(píng)論 17 410
  • 兩本不錯(cuò)的書: 《Python參考手冊(cè)》:對(duì)Python各個(gè)標(biāo)準(zhǔn)模塊悦污,特性介紹的比較詳細(xì)。 《Python核心編程...
    靜熙老師哈哈哈閱讀 3,360評(píng)論 0 80
  • 又夢(mèng)到你了 一整個(gè)晚上的夢(mèng)都是你 一個(gè)好的結(jié)局 你點(diǎn)頭答應(yīng)和我和好了
    Dejavuu閱讀 132評(píng)論 0 0
  • 也曾烏煙瘴氣的生活過钉蒲,也曾把吃喝嫖賭當(dāng)作人生目標(biāo)切端,也曾藐視鄙視過世間的茍且。最終還是選擇了相信這世界的善顷啼,相信終有...
    滿樹核桃閱讀 215評(píng)論 0 0
  • 一踏枣,概念 回顧下個(gè)人利潤表和公司利潤表昌屉,每個(gè)月,我們領(lǐng)到的工資扣除一系列支出和稅之后茵瀑,生下來的錢越多越好间驮,公司也是...
    文龍雕心閱讀 247評(píng)論 0 1