可變參數(shù)
可變參數(shù)就是傳入的參數(shù)個(gè)數(shù)是可變的脸候,可以是1個(gè)顽素、2個(gè)到任意個(gè)粱胜,還可以是0個(gè)
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
定義可變參數(shù)和定義一個(gè)list或tuple參數(shù)相比飒硅,僅僅在參數(shù)前面加了一個(gè)*號(hào)砂缩。在函數(shù)內(nèi)部作谚,參數(shù)numbers接收到的是一個(gè)tuple,因此庵芭,函數(shù)代碼完全不變妹懒。但是,調(diào)用該函數(shù)時(shí)双吆,可以傳入任意個(gè)參數(shù)眨唬,包括0個(gè)參數(shù)如果已經(jīng)有一個(gè)list或者tuple,要調(diào)用一個(gè)可變參數(shù)怎么辦好乐?Python允許你在list或tuple前面加一個(gè)*號(hào)匾竿,把list或tuple的元素變成可變參數(shù)傳進(jìn)去:
>>>nums = [1, 2, 3]
>>> calc(*nums)
14
*nums表示把nums這個(gè)list的所有元素作為可變參數(shù)傳進(jìn)去。這種寫法相當(dāng)有用蔚万,而且很常見(jiàn)岭妖。
關(guān)鍵字參數(shù)
關(guān)鍵字參數(shù)允許你傳入0個(gè)或任意個(gè)含參數(shù)名的參數(shù),這些關(guān)鍵字參數(shù)在函數(shù)內(nèi)部自動(dòng)組裝為一個(gè)dict笛坦。請(qǐng)看示例
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
函數(shù)person除了必選參數(shù)name和age外区转,還接受關(guān)鍵字參數(shù)kw。在調(diào)用該函數(shù)時(shí)版扩,可以只傳入必選參數(shù)废离,當(dāng)傳入額外參數(shù)時(shí),可以先用dict包裝礁芦,然后用像可變參數(shù)一樣的用法
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
extra表示把extra這個(gè)dict的所有key-value用關(guān)鍵字參數(shù)傳入到函數(shù)的**kw參數(shù)蜻韭,kw將獲得一個(gè)dict,注意kw獲得的dict是extra的一份拷貝柿扣,對(duì)kw的改動(dòng)不會(huì)影響到函數(shù)外的extra肖方。
Python的函數(shù)具有非常靈活的參數(shù)形態(tài),既可以實(shí)現(xiàn)簡(jiǎn)單的調(diào)用未状,又可以傳入非常復(fù)雜的參數(shù)俯画。
默認(rèn)參數(shù)一定要用不可變對(duì)象,如果是可變對(duì)象司草,程序運(yùn)行時(shí)會(huì)有邏輯錯(cuò)誤艰垂!
要注意定義可變參數(shù)和關(guān)鍵字參數(shù)的語(yǔ)法:
*args是可變參數(shù),args接收的是一個(gè)tuple埋虹;
**kw是關(guān)鍵字參數(shù)猜憎,kw接收的是一個(gè)dict。
以及調(diào)用函數(shù)時(shí)如何傳入可變參數(shù)和關(guān)鍵字參數(shù)的語(yǔ)法:
可變參數(shù)既可以直接傳入:func(1, 2, 3)搔课,又可以先組裝list或tuple胰柑,再通過(guò)args傳入:func((1, 2, 3));
關(guān)鍵字參數(shù)既可以直接傳入:func(a=1, b=2),又可以先組裝dict柬讨,再通過(guò)kw傳入:func({'a': 1, 'b': 2})崩瓤。
使用args和*kw是Python的習(xí)慣寫法,當(dāng)然也可以用其他參數(shù)名姐浮,但最好使用習(xí)慣用法谷遂。
命名的關(guān)鍵字參數(shù)是為了限制調(diào)用者可以傳入的參數(shù)名,同時(shí)可以提供默認(rèn)值卖鲤。
定義命名的關(guān)鍵字參數(shù)在沒(méi)有可變參數(shù)的情況下不要忘了寫分隔符*肾扰,否則定義的將是位置參數(shù)。
尾遞歸
使用遞歸函數(shù)需要注意防止棧溢出蛋逾。在計(jì)算機(jī)中集晚,函數(shù)調(diào)用是通過(guò)棧(stack)這種數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,每當(dāng)進(jìn)入一個(gè)函數(shù)調(diào)用区匣,棧就會(huì)加一層棧幀偷拔,每當(dāng)函數(shù)返回,棧就會(huì)減一層棧幀亏钩。由于棧的大小不是無(wú)限的莲绰,所以,遞歸調(diào)用的次數(shù)過(guò)多姑丑,會(huì)導(dǎo)致棧溢出蛤签。
解決遞歸調(diào)用棧溢出的方法是通過(guò)尾遞歸優(yōu)化,事實(shí)上尾遞歸和循環(huán)的效果是一樣的栅哀,所以震肮,把循環(huán)看成是一種特殊的尾遞歸函數(shù)也是可以的。
尾遞歸是指留拾,在函數(shù)返回的時(shí)候戳晌,調(diào)用自身本身,并且痴柔,return語(yǔ)句不能包含表達(dá)式沦偎。這樣,編譯器或者解釋器就可以把尾遞歸做優(yōu)化咳蔚,使遞歸本身無(wú)論調(diào)用多少次扛施,都只占用一個(gè)棧幀,不會(huì)出現(xiàn)棧溢出的情況屹篓。
def fact_iter(num, product):
if num == 1:
return product
return fact_iter(num - 1, num * product)
可以看到,return fact_iter(num - 1, num * product)僅返回遞歸函數(shù)本身匙奴,num - 1和num * product在函數(shù)調(diào)用前就會(huì)被計(jì)算堆巧,不影響函數(shù)調(diào)用。