天天看點

《編寫高品質Python代碼的59個有效方法》——第18條:用數量可變的位置參數減少視覺雜訊

本節書摘來自華章社群《編寫高品質python代碼的59個有效方法》一書中的第18條:用數量可變的位置參數減少視覺雜訊,作者[美]布雷特·斯拉特金(brett slatkin),更多章節内容可以通路雲栖社群“華章社群”公衆号檢視

第18條:用數量可變的位置參數減少視覺雜訊

令函數接受可選的位置參數(由于這種參數習慣上寫為*args,是以又稱為star args,星号參數),能夠使代碼更加清晰,并能減少視覺雜訊(visual noise)。

例如,要定義log函數,以便把某些調試資訊列印出來。假如該函數的參數個數固定不變,那它就必須接受一段資訊及一份含有待列印值的清單。

即便沒有值要列印,隻想列印一條消息,調用者也必須像上面那樣,手工傳入一份空清單。這種寫法既麻煩,又顯得雜亂。最好是能令調用者把第二個參數完全省略掉。若想在python中實作此功能,可以把最後那個位置參數前面加個*,于是,對于現在的log函數來說,隻有第一個參數message是調用者必須要指定的,該參數後面,可以跟随任意數量的位置參數。函數體不需要修改,隻需修改調用該函數的代碼。

如果要把已有的清單,傳給像log這樣帶有變長參數的函數,那麼調用的時候,可以給清單前面加上*操作符。這樣python就會把這個清單裡的元素視為位置參數。

接受數量可變的位置參數,會帶來兩個問題。

第一個問題是,變長參數在傳給函數時,總是要先轉化成元組(tuple)。這就意味着,如果用帶有*操作符的生成器為參數,來調用這種函數,那麼python就必須先把該生成器完整地疊代一輪,并把生成器所生成的每一個值,都放入元組之中。這可能會消耗大量記憶體,并導緻程式崩潰。

隻有當我們能夠确定輸入的參數個數比較少時,才應該令函數接受*arg式的變長參數。在需要把很多字面量或變量名稱一起傳給某個函數的場合,使用這種變長參數,是較為理想的。該參數主要是為了簡化程式員的程式設計工作,并使得代碼更加易讀。

使用*arg參數的第二個問題是,如果以後要給函數添加新的位置參數,那就必須修改原來調用該函數的那些舊代碼。若是隻給參數清單前方添加新的位置參數,而不更新現有的調用代碼,則會産生難以調試的錯誤。

問題在于:上面的第二條log語句是以前寫好的,當時的log函數還沒有sequence參數,現在多了這個參數,使得7從values值的一部分,變成了message參數的值。這種bug很難追蹤,因為現在這段代碼仍然可以運作,而且不抛出異常。為了徹底避免此類情況,我們應該使用隻能以關鍵字形式指定的參數(keyword-only argument),來擴充這種接受*args的函數(參見本書第21條)。

要點

在def語句中使用*args,即可令函數接受數量可變的位置參數。

調用函數時,可以采用*操作符,把序列中的元素當成位置參數,傳給該

函數。

對生成器使用*操作符,可能導緻程式耗盡記憶體并崩潰。

在已經接受*args參數的函數上面繼續添加位置參數,可能會産生難以排查的bug。