**: 收藏參考
在python中常常看到有這樣的函式,它們的入口引數的個數是不定的。比如有如下**
in: print zip([1, 2],[3, 4])
out: [(1, 3), (2, 4)]
in: print zip([1, 2],[3, 4],[5, 6])
out: [(1, 3, 5), (2, 4, 6)]
其中zip是python自帶的乙個函式,其作用麼,相信聰明的你已經看出來了。那如果有一天我們也要寫乙個能接受任意輸入個數的python函式,該如何實現呢?
今天我就遇到這個問題,然後花了一點時間解決了——答案是,借助*
這個符號。雖然這是個很基礎的問題,網上資料很多,但還是想自己總結一下。
我們不妨先定義乙個灰常簡單的函式——實現兩個整數相加
def add_2_int(a1, a2):
return a1+a2
一目了然,這就好比剛學程式設計時的print "hello world!"
。
不滿足於此的我們,總想搞個大新聞——比如
實現多個整數的相加,但,事先不知道有幾個整數。這時我們就需要再學習乙個——借助萬能的
*
,來改寫原函式:
def add_int(*a):
s = 0
for e in a:
s += e return s
我們先不管函式是怎麼定義的、*a
是什麼含義,我們先看下怎麼呼叫這個函式
in: print add_int(1, 2)
out: 3 in: print add_int(1, 2, 3)
out: 6
無論輸入幾個整數,都能求和,可見,這個函式已經能實現我們想要的功能了。
回過頭看,這裡呼叫add_int
時輸入引數是三個:1,2,3
,但給add_int
定義的輸入是*a
,那*
的作用到底是什麼呢?其實就是在呼叫函式時,把輸入的三個引數1,2,3
打包成乙個元組(tuple),即打包成(1,2,3)
給a
這個引數,為了證明這點,我們不妨在函式中間加乙個print
語句
def add_int(*a):
s = 0
print "input a is: ", a for e in a:
s += e return s
呼叫函式並看下輸出:
in: print add_int(1, 2, 3)
out: input a is: (1, 2, 3) 6
確實若我們所料。
這時我們腦洞開始變大了,如果我輸入不是三個1,2,3
,而是本身是乙個列表[1,2,3]
,會不會也能實現求和呢?比如有如下**
a_list = [1, 2, 3]print add_int(a_list)
啊哦,報錯了:unsupported operand type(s) for +=: 'int' and 'list'
,說list
不能跟int
相加。我們分析一下,按照剛剛的理論,這裡呼叫add_int
時,只給了乙個引數a_list
,於是*a
會將a_list
打包成(a_list, )
給a
,當我們執行for e in a
語句時,得到的是a
裡面的每個元素,也就是a_list
,而不是a_list
裡面的元素,所以顯然無法得到想要的結果。
既然上面報錯了,那我們索性將錯就錯,設計乙個函式
實現任意多個我們只需修改函式list
的『相加』——對於list
而言+
就是連線
add_int
中用於存放累加結果的變數s
即可,即:
def add_list(*a):
s = # 因為要返回list,所以s的初始值是而不是0
for e in a:
s += e return s
比如我們要連線三個list
:[1,2]
,[3,4]
,[5,6]
,只需呼叫add_list([1, 2],[3, 4],[5, 6])
即可得到[1, 2, 3, 4, 5, 6]
注意,上面我們說來說去,都是在函式定義階段使用*
來打包(繫鈴),使得函式能接受任意多的入口引數個數。現在遇到乙個新問題:
給定兩個整數求和函式(即上面的暫時忘卻剛說到的add_2_int(a1, a2)
),現在有乙個元組a_tuple = (1, 2)
,求1+2
*
,為了解決這個問題,一般我們會逐個取出a_tuple
裡的1
,2
,然後再呼叫函式,比如add_2_int(a_tuple[0], a_tuple[1])
。有沒有更簡潔的方法呢?比如我們能否用某種手段使得輸入的a_tuple
自動拆開(解鈴)成兩個引數1, 2
再輸入函式呢?
答案是肯定的——還是用*
,寫成add_2_int(*a_tuple)
,注意,現在是函式呼叫階段,這裡*
的作用跟定義函式時恰恰相反,是將a_tuple
從(1,2)
拆開成1, 2
兩個引數輸入函式,對應函式的兩個入口引數a1, a2
(擴充套件一下,這種函式的引數傳遞方式在python中叫按位置傳遞
,還有按關鍵字傳遞
的方法,本文就不細說了)
其實上面這個問題的想法**很樸素——既然*
可以在函式定義時把入口引數『打包』成tuple型別,那我在函式呼叫時,也可以將tuple型別的變數『解壓』成乙個乙個的入口引數。那麼問題就來了,延續上述問題,我把問題變成:
給定不怕不怕,我們發現在解鈴階段(即函式呼叫階段),add_2_int(a1, a2)
,現在有乙個列表a_list = [3, 4]
,乙個集合a_set = set([6, 5])
,求3+4
和5+6
*
不光能拆開tuple
型別,包括set
,list
等通通可以,也就是通通可以這樣呼叫函式:add_2_int(*a_list)
,add_2_int(*a_set)
。
如果你腦洞再開啟一點,之前我們用*
定義了add_int(*a)
函式,現在有a_list=[1,2,3]
,那麼我們呼叫add_int(*a_list)
會產生什麼效果呢?
本文簡單實驗了一下*
在python函式中的作用,主要是區分函式定義和函式呼叫兩個階段,我把它稱作繫鈴和解鈴。
如果本文能對你編寫python函式有所幫助,也不枉鄙人熬夜啦善莫大焉~
Python給函式傳遞不定個數的引數
在python中常常看到有這樣的函式,它們的入口引數的個數是不定的。比如有如下 in print zip 1,2 3,4 out 1,3 2,4 in print zip 1,2 3,4 5,6 out 1,3,5 2,4,6 其中zip是python自帶的乙個函式,其作用麼,相信聰明的你已經看出來...
不定引數函式
引數的儲存位置 實參在傳遞值時,給形參申請空間並賦值,其形參在位址上形參的位址是相鄰的 根據編譯器和系統環境可能會有所不同 a b 4 sizeof int 乙個int位元組 int func int a,int b 正如上文所說,如果每次通過p 定址,程式的不具有良好的可移植性。c語言有乙個標頭檔...
函式不定引數
函式引數是以資料結構 棧的形式訪問,從右至左入棧.1.va list用於宣告乙個變數,我們知道函式的可變引數列表其實就是乙個字串,所以va list才被宣告為字元型指標,這個型別用於宣告乙個指向引數列表的字元型指標變數,例如 va list ap ap arguement pointer 2.va ...