Python中*args和**kwargs的作用
寫(xiě)在前面
讀代碼的過(guò)程中經(jīng)常見(jiàn)到這種含*args和**kwargs的表達(dá):
比如這個(gè)該輸出什么呢?
def foo(*args):
print(args)
foo(1, 2, 3, 4, 5)這個(gè)呢?
def foo(a, *args):
print('a:', a)
print('args:', args)
foo(1, 2, 3, 4, 5)還有這個(gè)呢?
def bar(a,b,c):
print(a,b,c)
bar(*[1,2,3])咦?∗號(hào)怎么出現(xiàn)在了一個(gè)列表前面?這樣對(duì)嗎?
*args和**kwargs,以及單獨(dú)的*,**到底是啥作用呢?原理是啥呢?讀完這篇文章你就徹底明白了!
*args有兩部分構(gòu)成為——*和args。這里的重點(diǎn)是*。
所以為了講清楚*args,我們要追根溯源——理解*的作用。
這里敲黑板,重點(diǎn)來(lái)了,這也是很多博客寫(xiě)的沒(méi)有寫(xiě)到的地方:∗的作用,有2個(gè)——打包參數(shù)(pack)和拆分參數(shù)(unpack)!
*argc
打包參數(shù)
例1:
def foo(*number):
print(number)
foo(1, 2, 3, 4, 5)(1, 2, 3, 4, 5)
我們看到了什么?給函數(shù)5個(gè)參數(shù),成功運(yùn)行了,而且輸出是參數(shù)構(gòu)成的元組。
我們知道,如果number前不加∗號(hào),那么很明顯foo()只能接受1個(gè)參數(shù),參數(shù)給多了少了都要報(bào)錯(cuò)。而加上∗,就能成功運(yùn)行。
那么原理是什么呢?
答案是:∗把函數(shù)foo()接受到的多個(gè)參數(shù)1,2,3,4,5,打包成了元組(1,2,3,4,5),賦值給了形參number。
我們可以驗(yàn)證一下:
例2:
def foo(*number):
for i in number:
print(i)
print(type(number))
foo(1, 2, 3, 4, 5)1
2
3
4
5
<class 'tuple'>
從例2可以看出,number確實(shí)被賦予了(1,2,3,4,5)這個(gè)實(shí)參。
說(shuō)話要講道理,詳情參見(jiàn)python官方文檔,這里粘個(gè)圖過(guò)來(lái):

例3:
def foo(a, *number):
print('a:', a)
print('number:', number)
for i in number:
print(i)
print(type(number))
foo(1, 2, 3, 4, 5)a: 1 number (2, 3, 4, 5) 2 3 4 5 <class 'tuple'>
從例3可以看出,number接受到的實(shí)參變成了(2,3,4,5),第一個(gè)參數(shù)1被形參a接受走了。
所以這里我們可以給出∗作用的完整版:
∗的作用:函數(shù)接受實(shí)參時(shí),按順序分配給函數(shù)形參,如果遇到帶∗的形參,那么就把還未分配出去的實(shí)參以元組形式打包(pack),分配給那個(gè)帶∗的形參。
可以再多幾個(gè)例子驗(yàn)證:
例4:
def foo(a, b, *number):
print('a:', a)
print('b:', b)
print('number:', number)
for i in number:
print(i)
print(type(number))
foo(1, 2, 3, 4, 5)a: 1 b: 2 number: (3, 4, 5) 3 4 5 <class 'tuple'>
例5:
def foo(a, b, *number, c):
print('a:', a)
print('b:', b)
print('c:', c)
print('number:', number)
for i in number:
print(i)
print(type(number))
foo(1, 2, 3, 4, 5)Traceback (most recent call last):
File "C:/Users/PycharmProjects/untitled10/test19.py", line 11, in <module>
foo(1, 2, 3, 4, 5)
TypeError: foo() missing 1 required keyword-only argument: 'c'注意例5我特地找了個(gè)報(bào)錯(cuò)的例子。自己分析一下為啥會(huì)報(bào)錯(cuò)。答案是:c前面的參數(shù)帶∗,把剩下的實(shí)參都接受走了,c沒(méi)有傳入實(shí)參!
到這里,∗的打包(pack)就解釋清楚了。
還留一個(gè)小尾巴:args是啥?
答案是:args僅僅是一個(gè)約定俗成的形參的寫(xiě)法,你寫(xiě)成把別的也沒(méi)事,但是不利于統(tǒng)一形式。就像我們的例子里,一直用的number,也照樣運(yùn)行正確。
拆分參數(shù)
例6:
def bar(a,b,c):
print(a,b,c)
bar(*[1,2,3])1 2 3
可以看出,∗這次沒(méi)有用在函數(shù)定義中,而是用在了函數(shù)調(diào)用中。在本例中的作用是啥呢?
答案是:把打包了的實(shí)參(元組或列表),拆分(unpack)成單個(gè)的,依次賦值給函數(shù)的形參。
在本例中,打包了的實(shí)參[1,2,3]被拆分,1賦值給了形參a,2賦值給了形參b,3賦值給了形參c。
∗拆分的作用就這么簡(jiǎn)單。理解了原理,其他的萬(wàn)變不離其宗。出兩個(gè)題,練習(xí)一下:
練習(xí):以下3段程序中,哪個(gè)可以正常運(yùn)行?
例7:
def bar(a,b):
print(a,b)
bar(*[1, 2, 3])例8:
def bar(a, b, c, d):
print(a, b, c, d)
bar(*[1, 2, 3])例9:
def bar(a, b, c, d=10):
print(a, b, c, d)
bar(*[1, 2, 3])答案是只有例9可以正常運(yùn)行。因?yàn)榘凑瘴覀冎v的原理,例7的實(shí)參3沒(méi)有對(duì)應(yīng)的形參接受,例8的形參d沒(méi)有實(shí)參賦值。
**kwargs
打包參數(shù)
上邊*args學(xué)懂了**kwargs也就很容易明白了。**kwargs也有兩部分構(gòu)成為——**和kwargs。這里的重點(diǎn)是∗∗。沒(méi)錯(cuò),kwargs僅僅是一個(gè)約定俗成的寫(xiě)法,沒(méi)有其他特殊含義,換成其他的也照用不誤,但是為了代碼可讀性,最好還是用約定俗成的。
∗∗的作用同樣也有兩個(gè)——打包參數(shù)(pack)和拆分參數(shù)(unpack)!
但是區(qū)別還是有的,簡(jiǎn)單來(lái)說(shuō)就是:
打包(pack):*args是把多個(gè)位置參數(shù)打包成元組,**kwargs是把多個(gè)關(guān)鍵字參數(shù)打包成字典。
拆分(unpack):*args是把打包了的參數(shù)拆成單個(gè)的,依次賦值給函數(shù)的形參,**kwargs是把字典的鍵值拆成單個(gè)的,依次賦值給函數(shù)的形參。
例10
def bar(**number):
print(number)
bar(a=1, b=2, c=3){'a': 1, 'b': 2, 'c': 3}
拆分參數(shù)
例11
def bar(a, b, c):
print(a,b,c)
bar(**{'a': 1, 'b': 2, 'c': 3})1 2 3
注意這里有個(gè)需要注意的地方,就是用∗∗方式拆解字典給形參賦值時(shí),需要字典的鍵名和函數(shù)形參一直,否則會(huì)報(bào)錯(cuò),自己試試就知道了。
位置參數(shù),關(guān)鍵字參數(shù),*args,**kwargs混用是要有一定順序的,這里我特地不寫(xiě)了。因?yàn)檫@問(wèn)題本身應(yīng)該不是個(gè)問(wèn)題,是學(xué)習(xí)函數(shù)時(shí)應(yīng)該打下的基本功。如果真的需要,可以自己再查一下,加深印象,也比在我這伸手就拿來(lái)的好。
到此這篇關(guān)于Python中*args和**kwargs的理解的文章就介紹到這了,更多相關(guān)Python *args和**kwargs內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python中的NumPy實(shí)用函數(shù)整理之percentile詳解
這篇文章主要介紹了Python中的NumPy實(shí)用函數(shù)整理之percentile詳解,NumPy函數(shù)percentile()用于計(jì)算指定維度上數(shù)組元素的第?n?個(gè)百分位數(shù),返回值為標(biāo)量或者數(shù)組,需要的朋友可以參考下2023-09-09
對(duì)pandas寫(xiě)入讀取h5文件的方法詳解
今天小編就為大家分享一篇對(duì)pandas寫(xiě)入讀取h5文件的方法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
Python企業(yè)編碼生成系統(tǒng)總體系統(tǒng)設(shè)計(jì)概述
這篇文章主要介紹了Python企業(yè)編碼生成系統(tǒng)總體系統(tǒng)設(shè)計(jì),簡(jiǎn)單描述了Python企業(yè)編碼生成系統(tǒng)的功能、結(jié)構(gòu)與相關(guān)編碼實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-07-07
linux centos 7.x 安裝 python3.x 替換 python2.x的過(guò)程解析
這篇文章主要介紹了linux centos 7.x 安裝 python3.x 替換 python2.x的過(guò)程解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
Python使用循環(huán)神經(jīng)網(wǎng)絡(luò)解決文本分類(lèi)問(wèn)題的方法詳解
這篇文章主要介紹了Python使用循環(huán)神經(jīng)網(wǎng)絡(luò)解決文本分類(lèi)問(wèn)題的方法,結(jié)合實(shí)例形式詳細(xì)分析了Python神經(jīng)網(wǎng)絡(luò)相關(guān)概念、原理及解決文本分類(lèi)具體操作技巧,需要的朋友可以參考下2020-01-01
python 通過(guò) pybind11 使用Eigen加速代碼的步驟
這篇文章主要介紹了python 通過(guò) pybind11 使用Eigen加速代碼的步驟,幫助大家更好的理解和使用python,感興趣的朋友可以了解下2020-12-12
關(guān)于Python常用模塊時(shí)間模塊time
這篇文章主要介紹了關(guān)于Python常用模塊時(shí)間模塊time,這個(gè)模塊是Python自帶的,我們不需要去下載,直接導(dǎo)入就可以使用,需要的朋友可以參考下2023-04-04
Python實(shí)現(xiàn)多路視頻多窗口播放功能
這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)多路視頻多窗口播放功能的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-02-02

