Python編程:定義函數(shù)輸入?yún)?shù)很簡單?這些規(guī)則掌握了沒?
?本文內(nèi)容主要涉及如下幾個(gè)主題方法,文章有點(diǎn)長,請(qǐng)收藏以便查閱。
函數(shù)參數(shù)即為函數(shù)的輸入,可分類為五組。
- 位置或關(guān)鍵字參數(shù):同時(shí)允許位置和關(guān)鍵字參數(shù);
- 可變位置參數(shù):在元組中收集任意數(shù)量的位置參數(shù);
- 可變關(guān)鍵字參數(shù):在字典中收集任意數(shù)量的關(guān)鍵字參數(shù);
- 僅限位置參數(shù):只能作為位置參數(shù)傳遞;
- 僅限關(guān)鍵字參數(shù):只能作為關(guān)鍵字參數(shù)傳遞。
到目前為止,我們所看到的例子中,看到的所有參數(shù)都是普通的位置參數(shù)或關(guān)鍵字參數(shù)。也已經(jīng)了解了如何將它們作為位置參數(shù)和關(guān)鍵字參數(shù)傳遞。關(guān)于它們沒有太多要說的了,所以我們要來看看其他類別。在此之前,先來看看可選參數(shù)。
1.可選參數(shù)
除了我們?cè)谶@里看到的類別之外,參數(shù)還可以分為必選項(xiàng)和可選項(xiàng)??蛇x參數(shù)有默認(rèn)值,其值在函數(shù)定義中指定。語法是格式為:name=value。示例如下:
這里,a是必需傳遞參數(shù)項(xiàng),而b的默認(rèn)值是4,c的默認(rèn)值是88,兩者是可選項(xiàng)。重要的是要注意,除了只有關(guān)鍵字的形參外,必需型形參必須始終位于函數(shù)定義中所有可選形參的左側(cè)。試著在上面的例子中刪除c的默認(rèn)值,看看會(huì)發(fā)生什么。
2.不定量位置參數(shù)
有時(shí),可能不希望為函數(shù)指定位置參數(shù)的確切數(shù)量,而Python通過使用可變位置參數(shù)提供了實(shí)現(xiàn)這一點(diǎn)的能力。讓我們來看一個(gè)非常常見的用例,minimum()函數(shù)。
這是一個(gè)計(jì)算其輸入值最小值的函數(shù),代碼如下:
如上所見,當(dāng)我們定義一個(gè)帶有星號(hào)*的形參時(shí),我們是在告訴Python,當(dāng)函數(shù)被調(diào)用時(shí),這個(gè)形參將收集數(shù)量不定的位置實(shí)參。在函數(shù)中,n是一個(gè)元組??扇∠a中的注釋print(type(n))行,然后運(yùn)行程序并看看輸出。
注意,一個(gè)函數(shù)最多只能有一個(gè)不定量位置參數(shù)——有更多的位置參數(shù)是沒有意義的。Python將無法決定如何劃分它們之間的參數(shù)。您也無法為變量位置參數(shù)指定默認(rèn)值。默認(rèn)值總是一個(gè)空元組。
提示:
是否注意到代碼中是如何用一個(gè)簡單的if n:檢查n是否為空的?這是因?yàn)樵赑ython中,集合對(duì)象在非空時(shí)求值為True,否則為False。元組、集合、列表、字典等等都是如此。
另一件需要注意的事情是,當(dāng)調(diào)用不帶參數(shù)的函數(shù)時(shí),可能想拋出一個(gè)錯(cuò)誤,而不是靜默地什么都不做。在這種情況下,我們不關(guān)心如何使這個(gè)函數(shù)健壯,而是要理解可變量位置參數(shù)。
另外,是否注意到,定義不定量位置形參的語法與可迭代解包的語法非常相似?這并非巧合。畢竟,這兩個(gè)特征互為鏡像。它們也經(jīng)常一起使用,因?yàn)椴欢课恢眯螀⒆屇悴槐負(fù)?dān)心解包的可迭代對(duì)象的長度是否與函數(shù)定義中的形參數(shù)量相匹配。
3.不定量關(guān)鍵字參數(shù)
不定量關(guān)鍵字參數(shù)(Variable keyword parameters)非常類似于不定量位置參數(shù)。唯一的區(qū)別是語法(**而不是*)和它們以字典形式被收集的事實(shí):
如上所示,在函數(shù)定義的參數(shù)名稱前添加**告訴Python使用該名稱來收集數(shù)量不定的關(guān)鍵字參數(shù)。與不定量位置參數(shù)的情況一樣,每個(gè)函數(shù)最多只能有一個(gè)可變關(guān)鍵字參數(shù),并且不能指定默認(rèn)值。
就像可變量位置參數(shù)類似于可迭代解包一樣,可變關(guān)鍵字參數(shù)類似于字典解包。字典解包也經(jīng)常用于將參數(shù)傳遞給具有可變量關(guān)鍵字形參的函數(shù)。
為什么能夠傳遞可變數(shù)量的關(guān)鍵字參數(shù)如此重要,目前可能還不清楚,那么通過如何使用這一能力的示例,你將能更真實(shí)的理解其重要性。
我們定義一個(gè)連接到數(shù)據(jù)庫的函數(shù):我們希望通過不帶參數(shù)地調(diào)用這個(gè)函數(shù)來連接到默認(rèn)數(shù)據(jù)庫。還希望通過向函數(shù)傳遞適當(dāng)?shù)膮?shù)來連接到任何其他數(shù)據(jù)庫。在你繼續(xù)讀下去之前,自己試著花幾分鐘自己想出一個(gè)解決方案:
注意,在函數(shù)中,我們可以準(zhǔn)備一個(gè)連接參數(shù)字典(conn_params)使用默認(rèn)值作為回退,其允許在函數(shù)調(diào)用時(shí)提供以覆蓋它們。有更好的方法可以用更少的代碼行來實(shí)現(xiàn)這一點(diǎn),但我們現(xiàn)在不關(guān)心這一點(diǎn)。運(yùn)行上述代碼會(huì)得到以下結(jié)果:
注意函數(shù)調(diào)用和輸出之間的對(duì)應(yīng)關(guān)系,以及如何根據(jù)傳遞給函數(shù)的內(nèi)容重寫默認(rèn)值。
4.僅限位置參數(shù)
從Python 3.8開始,PEP 570 (https://www.python.org/dev/peps/pep-0570/)引入了僅限位置的參數(shù)。有一種新的函數(shù)參數(shù)語法,/,表示一組函數(shù)形參必須在位置上指定,不能作為關(guān)鍵字參數(shù)傳遞。讓我們看一個(gè)簡單的例子:
在上面的例子中,我們定義了一個(gè)函數(shù)func(),它指定了三個(gè)參數(shù):a、b和c。函數(shù)簽名中的/表示a和b必須按位置傳遞,也就是說,不能通過關(guān)鍵字傳遞。
示例中的最后兩行顯示,我們可以按位置傳遞所有三個(gè)參數(shù)來調(diào)用函數(shù),或者可以按關(guān)鍵字傳遞c。這兩種情況都可以正常工作,因?yàn)閏定義在函數(shù)簽名中的/之后。如果我們?cè)噲D通過通過關(guān)鍵字傳遞a或b來調(diào)用函數(shù),像這樣:
這將產(chǎn)生如下類似回溯跟蹤信息:
前面的例子告訴我們,Python現(xiàn)在反饋給我們調(diào)用func()的方式,其意思是:通過關(guān)鍵字傳遞了參數(shù)b,但不允許這樣做。
僅限位置參數(shù)也可以是可選的,如下所示:
通過一些從官方文檔中借來的例子來看看這個(gè)特性給該語言帶來了什么。一個(gè)優(yōu)點(diǎn)是能夠完全模擬現(xiàn)有C編碼函數(shù)的行為:
另一個(gè)重要的用例是在形參名沒有啥有意義的幫助的情況下排除關(guān)鍵字實(shí)參:
在上面的例子中,obj關(guān)鍵字參數(shù)降低了可讀性。此外,如果我們希望重構(gòu)len函數(shù)的內(nèi)部結(jié)構(gòu),并將obj重命名為the_object(或任何其他名稱),更改保證不會(huì)破壞任何客戶端代碼,因?yàn)椴粫?huì)有任何對(duì)len()函數(shù)的調(diào)用,會(huì)涉及到現(xiàn)在已經(jīng)過時(shí)的obj參數(shù)名稱。
最后,使用僅限位置形參意味著/左邊的任何值都可以在不定量關(guān)鍵字實(shí)參中使用,如下例所示:
在函數(shù)簽名中保留參數(shù)名以便在**kwargs中使用的能力可以生成更簡單、更清晰的代碼。
現(xiàn)在來研究一下僅限位置類似版:僅限關(guān)鍵字參數(shù)。
5.僅限關(guān)鍵字參數(shù)
Python 3引入了僅限關(guān)鍵字的參數(shù)。我們只簡要地研究它們,因?yàn)樗鼈兊挠美⒉怀R?。有兩種方法可以指定它們,要么在不定量位置參數(shù)之后,要么在不定的*之后。來看兩個(gè)例子。代碼如下:
正如預(yù)期的那樣,函數(shù)kwo()接受數(shù)量可變的位置參數(shù)(a)和一個(gè)只有關(guān)鍵字的關(guān)鍵字c。調(diào)用的結(jié)果很簡單,你可以取消對(duì)第三個(gè)調(diào)用的注釋,以查看Python返回什么錯(cuò)誤。
同樣的情況也適用于函數(shù)kwo2(),它與kwo的不同之處在于,它接受一個(gè)位置參數(shù)a、一個(gè)關(guān)鍵字參數(shù)b和一個(gè)只有關(guān)鍵字的參數(shù)c。你可以取消對(duì)第三個(gè)調(diào)用的注釋,以查看產(chǎn)生的錯(cuò)誤。
現(xiàn)在應(yīng)已知道了如何指定不同類型的輸入?yún)?shù),接下來看看如何在函數(shù)定義中組合它們。
6.組合輸入?yún)?shù)
可以在同一個(gè)函數(shù)中組合不同的參數(shù)類型(事實(shí)上,這樣做通常非常有用)。就像在同一個(gè)函數(shù)調(diào)用中組合不同類型的實(shí)參一樣,在順序上有一些限制:
- 僅限位置的參數(shù)放在前面,然后跟隨一個(gè)斜杠“/”。
- 普通參數(shù)在任何僅限位置參數(shù)之后。
- 不定量位置參數(shù)在正常參數(shù)之后。
- 只有關(guān)鍵字參數(shù)在不定量位置參數(shù)之后。
- 不定量關(guān)鍵字參數(shù)總是排在最后。
對(duì)于僅限位置參數(shù)和普通參數(shù),任何必需的參數(shù)必須在任何可選參數(shù)之前定義。這意味著,如果你有一個(gè)可選的僅限位置參數(shù),那么所有常規(guī)參數(shù)也必須是可選的。該規(guī)則不影響僅限關(guān)鍵字的參數(shù)。
如果沒有例子,這些規(guī)則可能會(huì)有點(diǎn)難以理解,所以來看幾個(gè)示例:
注意函數(shù)定義中參數(shù)的順序。執(zhí)行該程序會(huì)得到以下結(jié)果:
現(xiàn)在再來看一個(gè)只有關(guān)鍵字參數(shù)的例子:
注意,在函數(shù)聲明中有僅限位置形參和僅限關(guān)鍵字形參:a僅限位置形參,而d和e僅限關(guān)鍵字形參。他們是在*args可變量位置參數(shù)之后,如果它們緊跟在單個(gè)*的后面,也會(huì)是一樣的(在這種情況下,將沒有任何可變位置參數(shù))。運(yùn)行程序會(huì)得到以下結(jié)果:
另一件需要注意的事情是我們?yōu)榭勺兞课恢脜?shù)和關(guān)鍵字參數(shù)命名。你可以自由選擇不同的名稱,但請(qǐng)注意,args和kwargs是這些參數(shù)的常規(guī)名稱,至少在一般情況下是這樣。
7.更多的簽名示例
為了簡要回顧一下使用僅限位置和關(guān)鍵字說明符的函數(shù)簽名,下面是一些進(jìn)一步的示例。省略不定量位置和關(guān)鍵字參數(shù),為簡潔起見,我們只剩下以下語法:
首先,我們有僅限位置的參數(shù),然后是位置或關(guān)鍵字參數(shù),最后是僅限關(guān)鍵字參數(shù)。
其他一些有效簽名如下:
以上均為有效簽名,下列為無效簽名:
你可以在官方文檔中閱讀語法規(guī)范:
https://docs.python.org/3/reference/compound_stmts.html#functiondefinitions
提示:在這一點(diǎn)上,要很好的理解與掌握,一個(gè)有用的練習(xí)方法是實(shí)現(xiàn)上述示例簽名中的任何一個(gè),打印出這些參數(shù)的值,就像我們?cè)谇懊娴木毩?xí)中所做的那樣,并以不同的方式傳遞參數(shù)。
8.避免陷阱!可變默認(rèn)值
要注意的一件事是,在Python中,默認(rèn)值是在定義時(shí)創(chuàng)建的;因此,根據(jù)默認(rèn)值的可變性,對(duì)同一函數(shù)的后續(xù)調(diào)用可能會(huì)有不同的行為。讓我們看一個(gè)例子:
兩個(gè)參數(shù)都有可變的默認(rèn)值。這意味著,如果執(zhí)行中影響了這些對(duì)象,任何修改都將停留在后續(xù)的函數(shù)調(diào)用中??纯茨闶欠衲芾斫膺@些調(diào)用的輸出:
是不是很搞事?雖然這種行為一開始看起來很奇怪,但它實(shí)際上是有意義的,而且非常方便——例如,當(dāng)使用“記憶”技術(shù)時(shí),就有了天生之才的傲嬌。更有趣的是,在調(diào)用之間,我們引入了一個(gè)不使用默認(rèn)值的函數(shù),比如:
運(yùn)行代碼輸出內(nèi)容如下所示:
這個(gè)輸出告訴我們,即使使用其他值調(diào)用函數(shù),默認(rèn)值也會(huì)被保留。我想到的一個(gè)問題是,如何每次都獲得一個(gè)新的空值?慣例是這樣的:
注意,通過使用前面的技術(shù),如果調(diào)用函數(shù)時(shí)沒有傳遞a,我們總是得到一個(gè)全新的空列表。
本文小結(jié)
本文詳細(xì)介紹了函數(shù)的輸入?yún)?shù)分類、示例和調(diào)用,都是圍繞如下主題展開:
位置或關(guān)鍵字參數(shù):同時(shí)允許位置和關(guān)鍵字參數(shù);
可變位置參數(shù):在元組中收集任意數(shù)量的位置參數(shù);
可變關(guān)鍵字參數(shù):在字典中收集任意數(shù)量的關(guān)鍵字參數(shù);
僅限位置參數(shù):只能作為位置參數(shù)傳遞;
?僅限關(guān)鍵字參數(shù):只能作為關(guān)鍵字參數(shù)傳遞。?