天天看點

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

本節書摘來自華章出版社《python樹莓派程式設計》一書中的第3章,第3.4節,作者:[美]沃爾弗拉姆·多納特(wolfram donat)著 韓德強 等譯,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

現在,你已經了解了資料類型。接下來,讓我們看看如何在實際程式中使用它們。當你建立一個python程式時,首先必須從編譯器的環境中退出來,并且打開一個文本編輯器,如emacs或者樹莓派的leafpad。在建立完程式後,将其”.py”的擴充名儲存。之後,你便可以通過輸入以下指令運作該程式:

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

在衆多的程式設計語言中,python的文法也十分與衆不同。python使用空格或者縮進來分開不同的代碼塊。c語言等其他語言用花括号區分不同的代碼塊,如if語句;python使用冒号和縮進來定義一個代碼塊。

c語言中的代碼格式如下所示:

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

在python中,相同的代碼如下所示:

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

你可能會注意關于python程式設計的兩個細節。第一,在if語句中括号的作用不是很明顯。在python中,括号不是必需的,但在大多數情況下,使用括号是一種好的程式設計習慣的表現,因為加了括号會提高代碼的可讀性。你也會發現,大多數其他的程式設計語言在每行代碼的末尾都會以分号結束,而python則不是這樣。這可能會花些功夫去适應,但卻可以避免因為在某處分号放錯位置或者忘記添加分号而引起編譯失敗的問題。在python中,每行代碼的末尾就是該條語句的末尾—就這麼簡單。

你已經見過一條語句的形式了,如:

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

同之前提到的一樣,在python中不需要提前聲明x是一個整型變量,y是一個字元型變量—python可以自己差別。這些語句稱作指派語句(assignment),它們将等号右邊的值賦給等号左邊的變量。不同的程式設計語言中有各種各樣的命名規則,但我能給你的最好建議是:選擇其中一個規則并堅持下去。如果你喜歡pascal語言的規則(thisisavariable),那就用這個規則。如果你更偏向于駝峰規則(thisisavariable),就使用這個規則。但一定要一緻,以後你會感謝你的堅持的。在任何情況下,無論變量是數值、字元、清單,或其他别的什麼,指派的工作僅僅是:将一個值賦給一個變量。這是程式設計函數中最簡單的一個。

3.4.1 if測試

接下來要介紹的程式設計函數是if語句,及其相關的elif和else函數。如你所預期的一樣,if執行了一個測試,然後選擇一項基于測試的結果。最基本的if語句如下所示:

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

'1'和布爾變量中的“true”效果一樣,是以上述語句總會輸出“true”。

當你在python終端或者idle中輸入if語句并以冒号結束時,下一個提示符永遠都是省略号(…),這意味着python正等待一個縮進塊。如果你已經進行了縮進操作,按下enter鍵結束等待。如果你在一個文本編輯器内編寫程式,確定在需要縮進時進行了縮進操作。

從此處開始,我将會按文本編輯器的格式書寫代碼,并将輸出的結果按照運作腳本之後的格式書寫。

這是一個使用elif和else的較複雜的程式,如下:

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

很明顯,這段代碼最終會輸出“spam is a wonderful thing!”。當程式執行時,計算機首先判斷第一個if,如果被判斷的語句是正确的,則會立即執行随後縮進塊内的代碼。如果不正确,則略過縮進塊尋找elif,并判斷其語句的正确性。同樣,如果正确或者沒有elif語句,計算機會執行後面縮進塊内的程式,如果不正确,則會跳過縮進塊尋找下一個elif或者else語句。

在此有三點需要注意:第一,如果一條if語句内的内容是錯誤的,則在之後的縮進塊内的内容都不會執行,計算機會直接跳轉到下一個未縮進的代碼處。

第二,同其他語言一樣,python使用雙等号來判斷是否相等。單等号用來進行指派操作,雙等号用來判斷。我之是以提起這個是因為每個程式員(我确定指的是每一個程式員)某些時候都會在if語句中使用單等号進行判斷操作,是以他們的程式會得到很多奇怪的結果。你也會犯同樣的錯誤,但我希望提前為你打個預防針。

第三,python忽略空行、空格(當然,除了在互動式情景及縮進塊内的狀況)和注釋。這點很重要,因為你可以随意标注你的代碼,以便提高它們對于其他程式員的可讀性,即便是以後你自己讀你的代碼也是一樣。

在python中,注釋通常以“#“開始,程式會忽略#後的一切内容。

代碼的可讀性是一個很重要的因素,希望你能定期回憶我這句話。你是希望試着調試先前編寫的代碼還是按照以下方式程式設計:

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

雖然沒什麼樂趣,但你可以很清楚地看懂第二種書寫方式的内容,在讀完類似的上百行沒有空格、空行或者注釋的代碼後,你的眼睛會感謝你相信我。讓我們看看使用空格後倒數第二行發生的變化:

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

你可以随意使用空格。

關于if部分,我最後想說的的内容是關于布爾操作符。在一個判斷正誤的測試中,x and y正确意味着x和y都正确。x or y正确則意味着x或者y正确,not x正确意味着x是錯的。python中使用關鍵詞進行布爾運算,而不像c或者c++中使用&&、||、!操作符。好好學習這些操作符,它們會變得十分順手的。

3.4.2 循環

通常,程式從頭至尾每一行執行一次。然而,一些特定的語句可能會使程式執行的順序從一點跳到另一點,這些控制流語句(control-flow statement)包括if(then)語句和循環。

最簡單的循環語句可能是執行很多次的一段代碼,例如:

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

之後會輸出:

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

也可使用for循環周遊字元串,或者是一個清單:

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

或者周遊字元并輸出周遊的内容:

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

盡管python中for循環的文法和c或java中的有些不同,不過一旦你适應了它們,使用這種文法就得心應手了。

第二種循環語句是while語句。這種語句判斷一個狀态,隻要狀态正确就會繼續執行縮進框内的程式,例如:

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計
《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

可能與你想象中的有些不同,這段代碼絕對不會輸出“10”,因為x輸出之後才會進行加1操作。在第10次循環過程中,編譯器輸出“9”之後x增加到10。而此時while條件不再為真,是以縮進框内的代碼也不會被執行。

如果你正等待一個特定事件的發生,如按鍵按下或者使用者按下“q”退出的操作,while語句就十分有用。讓我們看看接下來的例子:

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

這段代碼中有兩點值得注意:第一,在python 2.x版本中,raw_input指令用來得到使用者的一個輸入,而在python 3.x中,該指令則改為簡單的input了;第二,記得使用break指令,這條指令會跳出目前循環。是以在這種情況下,while中循環的部分會永遠循環,但當檢測var == 'q'傳回值為真時,程式會退出目前循環并結束程式。

3.4.3 函數

函數可以讓程式員編寫的代碼重複使用。它能大大提高工作效率。通常,如果你發現代碼中某些功能需要執行很多次,這個功能很有可能需要改寫為函數。

假設你編寫了一個簡單的程式用來計算矩形的面積和周長。使用者輸入矩形的高和寬,之後程式進行相應的計算。實作這個功能最簡單的方法是編寫一個帶參數的函數,其參數分别為矩形的高和寬。之後函數将矩形的面積和周長傳回給主程式。為了實作這個函數,我們用def指派語句進行編寫。def指派語句是我們定義一個函數的方法,其文法為def函數名(參數1,參數2):

《 Python樹莓派程式設計》——3.4 利用Python進行程式設計
《 Python樹莓派程式設計》——3.4 利用Python進行程式設計

這個小程式需要你提供一些參數并傳回計算的結果。可能這不是最好的例子(你可以用更少的代碼計算出結果),但卻很好地闡述了代碼複用的思想。通過這個函數,你就明白:在程式的任何位置,隻要你需要計算面積或者周長,調用areaperimeter函數并賦給參數“height”和“width”值即可。

在此需要注意一點:raw_input函數會傳回一個字元串,即便你輸入的是數字,傳回的也是字元串類型的值。這也就解釋了為什麼在areaperimeter函數中height和width變量在計算前必須要進行int轉換。

如果對其他語言比較熟悉的話,你會發現python的函數與其他語言的函數在方法、功能和步驟方面都有一些不同。例如,在python中,所有的函數都是按引用進行調用(call-by-reference)。不需要太過專業的術語,簡單而言,這意味着當你給函數傳遞一個參數時,你隻是将一個指針傳遞給一個變量,而不是傳遞數值。這種方式使得python的記憶體管理更加友善。例如,當你在函數中一遍又一遍地傳遞清單參數時,不需要複制整個清單的内容。具體而言,當一個函數将一個清單作為參數時,你傳遞的隻是清單首元素在記憶體中的位置,之後函數基于首元素的位置再查找剩餘項。

函數另一個有意思的方面是:它們都是可執行的語句。這意味着一個函數實際上可以在if語句中聲明和調用。雖然并不是很常見,但是這樣定義和調用是合法的(有時也十分有用)。def語句可以嵌套在循環當中,嵌套在其他的def語句中,甚至嵌套在清單和字典裡。

我們會在進行具體項目時回顧函數部分;現在,隻需要知道它們的存在,并知道它們對你自己編寫的每個程式都很實用即可。

3.4.4 對象和面向對象程式設計

在本章中,最後一件重要的事情是其與生俱來的執行面向對象代碼的能力。面向對象程式設計(object-oriented programming,oop)是一個較為進階的話題,可能不在本書讨論的範圍之内。但我認為這是一個十分重要的話題,不可輕描淡寫,一帶而過。

oop是一個程式資料被分為對象和函數(或方法)組合的範例。一個對象就是一個資料結構,通常是一組資料類型的結合,包括整型、字元型或者其他的資料類型。對象通常是類的一部分,與類中的方法相關聯,并通過方法操作。

也許解釋這部分最簡單的方法就是使用shape示例。在這個例子中,一個shape(形狀)是一個對象的類。類中有值,例如name(名稱)和numberofsides(面數)。這個類也有相關的函數,如findarea(計算面積)或者findperimeter(計算周長)。

shape類有很多子類,子類描述的内容更為具體。一個square(正方形)是一個shape的對象,它的shapetype(形狀屬性)值等于square,numberofsides值等于4。它的findarea函數接受numberofsides值,并将該值的平方作為傳回值。同時,一個triangle(三角形)對象也有不同的name、shapetype和numberofsides值和不同的findarea方法。

這個例子不僅簡單介紹了對象的概念,也闡述了繼承的概念—oop的一個組成部分。triangle對象從它的父類shape類繼承了name、numberofsides和findarea部分(雖然這幾個部分都具有不同的值或者實作方法)。如果一個對象繼承于shape類,它也會繼承那些部分。即便它不需要用到那些部分,它還是會包含這些部分。它可能會增加一些其他的部分(例如circle(圓形)對象可能會有radius(半徑)值),但它也會包含其父類的那些部分。

如果你在程式設計中用到這些類,相對于c++或者java而言,python更容易了解。無論屬性是一個對象或是一個方法,你都可以按照接下來的文法結構進行命名:object.attribute(對象.屬性)。如果你有一個叫作holygrail的circle對象,其半徑值用holygrail.radius來表示。一個名為unexplodedscotman的正方形,其計算面積的函數用unexplodedscotsman.findarea來定義。

如之前所述,oop的内容超出了本書涉及的範圍。但像函數這些概念卻十分有用,尤其是在很長很複雜的程式中。當你在學習python的過程中,請自由地進行探索吧。你會發現python也是一門功能豐富的語言,它甚至允許你執行其他進階程式任務。