- 零基礎入門學習Python(第2版)
- 小甲魚
- 1948字
- 2019-12-20 12:19:40
6.2 靈活即強大

視頻講解
有時候,評論一種編程語言是否優秀,往往是看它是否靈活。靈活并非意味著無所不能、無所不包,那樣就會顯得龐大和冗雜。靈活應該表現為多變,如前面學到的參數,函數因參數而靈活。如果沒有參數,一個函數就只能死板地完成一個功能、一項任務。
6.2.1 形參和實參
參數從調用的角度來說,分為形式參數(parameter)和實際參數(argument)(注:本書后面簡稱為“形參”和“實參”)。與絕大多數編程語言一樣,形參指的是函數定義的過程中小括號里的參數,而實參則指的是函數在被調用的過程中傳遞進來的參數。
舉個例子:

sayHi(name)中的name是一個形參,因為它只是代表一個位置、一個變量名;而調用sayHi("小甲魚")傳遞的"小甲魚"則是一個實參,因為它是一個具體的內容,是賦值到變量name中的值。
6.2.2 函數文檔
給函數寫文檔是為了讓后人可以更好地理解你的函數設計邏輯,對于一名優秀的程序員來說,養成編寫函數文檔的習慣無疑是非常必要的。因為在實際開發中,個人的工作量和能力確實相當有限,因此中、大型的程序永遠都是團隊來完成的。大家的代碼要相互銜接,就需要先閱讀別人提供的文檔,因此適當的文檔說明非常重要。而函數文檔的作用是描述該函數的功能以及一些注意事項:

例如該匯率轉換函數,因為匯率其實每天都在變化,所以如果沒有注明指定匯率的日期,就可能會導致數據產生偏差。
可以看到,函數開頭的幾行字符串并不會被打印出來,但它將作為函數的一部分存儲起來。這個字符串稱為函數文檔,它的功能與代碼注釋是一樣的。
有讀者可能會說,既然一樣,搞那么復雜干啥呀?其實也不是完全一樣,函數的文檔字符串可以通過特殊屬性_ _doc_ _獲取(注:_ _doc_ _兩邊分別是兩條下畫線):

另外,當想使用一個BIF卻又不確定其用法的時候,可以通過help()函數來查看函數的文檔:

6.2.3 關鍵字參數
前面在定義函數的時候,就已經把參數的名字和位置確定下來,Python中這類位置固定的參數稱為位置參數。對于函數的調用者來說,只需要知道按照順序傳遞正確的參數就可以了。
可是有些啥時候,粗心的程序員很容易會搞亂位置參數的順序,以至于函數無法按照預期實現。對于這類情況,使用關鍵字參數就很有用了。
舉個例子:

關鍵字參數其實就是在傳入實參時明確指定形參的變量名,其特點就是參數之間不存在先后順序。盡管使用這種技巧要多輸入一些字符,但隨著程序規模越大、參數越多的時候,關鍵字參數起到的作用就越明顯。畢竟寧可多輸入幾個字符,也不希望出現料想不及的BUG。
另外,在調用函數的時候,位置參數必須在關鍵字參數的前面,否則就會出錯:
>>> eat(something="蛋糕", "小甲魚") SyntaxError: positional argument follows keyword argument
6.2.4 默認參數
Python的函數允許為參數指定默認的值,那么在函數調用的時候如果沒有傳遞實參,則采用默認參數值:

可以看到,默認參數使得函數的調用更加便捷了。這就像日常安裝應用程序,可以選擇自定義或者默認安裝,我想絕大多數普通用戶都會選擇默認安裝的,對吧?
結合默認參數和關鍵字參數,可以使函數的調用變得非常靈活:

另外,在定義函數的時候,位置參數必須在默認參數的前面,否則就會出錯:
>>> def watchMovie(name="小甲魚", cigarette=True, beer=True, girlfriend): pass SyntaxError: non-default argument follows default argument
6.2.5 收集參數
這個名字看起來比較新鮮,其實大多數時候它也被稱為可變參數。有時候,可能函數也不知道調用者實際上會傳入多少個實參,這看起來很可笑,對嗎?其實不然,例如我們熟悉的print()函數就是這樣:
>>> print(1, 2, 3, 4, 5) 1 2 3 4 5 >>> print("I", "Love", "FishC") I Love FishC
若實參個數不確定,在定義函數的時候,形參就可以使用收集參數來“搞定”。而語法也很簡單,僅需要在參數前面加上星號(*)即可:

其實大家仔細思考后也不難理解,Python就是把標志為收集參數的參數們打包成一個元組。

不過這里需要注意一下,如果在收集參數后面還需要指定其他參數,那么在調用函數的時候就應該使用關鍵參數來指定,否則Python就都會把實參都納入到收集參數中。
舉個例子:

建議大家如果定義的函數中帶有收集參數,那么可以將其他參數設置為默認參數,例如,print()的原型如下:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
objects參數是一個收集參數,如果傳入多個參數,將依次打印出來;sep參數指定多個參數之間的分隔符,默認是空格;end參數指定以什么字符結束打印,默認是換行符;file參數指定輸出的位置;flush指定是否強制刷新緩存。
在函數的定義中,收集參數前面的星號(*)起到的作用稱為“打包”操作,通俗的理解就是將多個參數打包成一個元組的形式進行存儲。
在這里給大家介紹一個有趣的技能:星號(*)在形參中的作用是“打包”,而在實參中的作用則相反,起到“解包”的作用。
舉個例子:
>>> num = (1, 2, 3, 4, 5) >>> print(num) (1, 2, 3, 4, 5) >>> print(*num) 1 2 3 ?4 5
“解包”操作也適用于其他的序列類型:
>>> name = "FishC" >>> print(*name) F i s h C >>> list1 = [1, 1, 2, 3, 5] >>> print(*list1) 1 1 2 3 5
Python還有另一種收集方式,就是用兩個星號(**)表示。與前面的介紹不同,兩個星號的收集參數表示為將參數們打包成字典的形式。字典的概念還沒有接觸,所以在后面講解字典的章節中再給大家介紹吧。
- HTML5+CSS3+JavaScript從入門到精通:上冊(微課精編版·第2版)
- .NET之美:.NET關鍵技術深入解析
- 軟件項目估算
- Kali Linux Web Penetration Testing Cookbook
- Android開發精要
- Web開發的貴族:ASP.NET 3.5+SQL Server 2008
- Bulma必知必會
- Learning Network Forensics
- 51單片機C語言開發教程
- CoffeeScript Application Development Cookbook
- Hands-On Nuxt.js Web Development
- Getting Started with Polymer
- 超好玩的Scratch 3.5少兒編程
- 計算機系統解密:從理解計算機到編寫高效代碼
- Parallel Programming with Python