天天看點

《從問題到程式:用Python學程式設計和計算》——2.7 判斷和條件控制

本節書摘來自華章計算機《從問題到程式:用python學程式設計和計算》一書中的第2章,第2.7節,作者:裘宗燕 更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

數學裡有一些表示判斷的算符,如表示數值之間的等于或不等于、大于、小于等。python提供了一些用于描述條件判斷的運算符以及一種特殊的語句(稱為if語言,條件語句),它能利用條件判斷的結果選擇執行不同的語句或語句序列。

2.7.1 條件判斷和邏輯表達式

對于數值類型,這裡有一組比較運算符用于描述基本條件判斷,包括:

《從問題到程式:用Python學程式設計和計算》——2.7 判斷和條件控制

https://yqfile.alicdn.com/c363f0e3f86cee070abadc552943d7b640520f4a.png" >

用一個比較運算符和兩個數值表達式,可以構造出一個關系表達式,其意義就是判斷兩個數值之間的特定關系是否成立。

比較運算符也是一類運算符,求值一個關系表達式,也應該得到一個運算結果。python用兩個特殊的邏輯對象表示比較的結果,它們屬于内置的邏輯類型bool,是該類型中僅有的兩個對象,關鍵字true和false分别表示這兩個邏輯對象。在做比較時,關系成立就會得到true,表示結果是“真”;關系不成立時将得到false,表示比較的結論是“假”。例如,當20 > 15将得到true,而12 >= 15得到false。

用一個關系運算符可以描述兩個數值(表達式)之間的一種關系,但是這往往不夠。很多時候我們希望考慮若幹關系都成立等一些組合情況。例如,對于三角形的三條邊,基本要求是它們的值都大于0,為此就需要寫一個組合判斷。邏輯研究表明,隻需要三個邏輯組合運算,就足以描述所有的組合判斷,它們是:

1)a與b,表示a和b都成立的組合判斷;

2)a或b,表示a與b之中至少有一個成立的組合判斷;

3)非a,表示a不成立的組合判斷。

python為上面三個邏輯組合關系提供了三個運算符:

《從問題到程式:用Python學程式設計和計算》——2.7 判斷和條件控制

https://yqfile.alicdn.com/2ff53ef3ebf6b750465db4cdb7f399623e1643da.png" >

其中,or和and是二進制運算符,not是一進制運算符。假設a和b是具有邏輯值的表達式(比較表達式或組合邏輯表達式),當且僅當a和b都為真時a and b為真;當且僅當a和b中至少一個為真時a or b為真;當且僅當a為假時not a為真。這三個邏輯組合運算符都是關鍵字,基于關系和邏輯運算符構造起來的表達式稱為邏輯表達式。

例如,3 > 2 and 7 <= 10的值是true,因為3 > 2和7 <= 10都是正确的。not 3 > 2 or 7 > 10 or 7 > 5的值也是true,有關情況請讀者自己分析。顯然這裡也有運算符的優先級和結合性問題。

為友善書寫,python允許連續使用比較運算符。例如x > 1 and x < 10可以簡單地寫為1 < x < 10。實際上,在python裡還可以寫10 < x > y2,表示x > 10 and x > y2。這種形式在數學中不常見。

python關于比較運算符和邏輯運算符的優先級和結合性的規定如下:

比較運算符的優先級低于算術運算符,是以x + y > x2相當于(x + y) > (x2),是合法的關系表達式。所有比較運算符的優先級相同,連續的比較表示對相鄰運算對象做關系運算之後用and連接配接,互相為“與”關系。

三個邏輯運算符中,一進制運算符not的優先級最高,但低于比較運算符,or的優先級最低,and介于兩者之間。是以,not x2 > 5 or y < 6 and x y > 8相當于not (x2 > 5) or ((y < 6) and (x y > 8))。

例如,變量a、b、c的值構成一個三角形的三條邊,條件可以寫為:

這裡假定了a、b、c的值都是數值。由于表達式很長,這裡用了續行符,表示描述的是一個表達式,雖然其正文延續了兩行。

2.7.2 if語句(條件語句)

要想根據邏輯判斷選擇不同的處理方式,就要使用if語句,這種語句也常被稱為條件語句或者分支語句。if語句有兩種基本形式,其一是:

在這個語句執行時,如果表達式為真,就執行語句組中的語句(可以有一個或多個),全部執行完後if語句結束;表達式為假時什麼也不做,if語句直接結束。

第二種形式是:

如果語句執行時表達式為真,就執行第一個語句組中的語句;表達式為假時執行第二個語句組中的語句。執行完任一個語句組時整個if語句結束。

現在可以重寫基于三邊長求三角形面積的程式,加進輸入檢查:

本程式一次運作的情況如下:

程式的第一行就是注釋,也常被稱為注釋行。

if語句和程式格式

對一個if語句,從關鍵字if開始到相應語句組結束稱為該語句的if段,從關鍵字else開始的部分稱為其else段(else段可選,可以沒有)。其中的“if 表達式:”部分和“else:”部分稱為相應段的頭部,語句組稱為該段的體。

與前面各種簡單語句相對應,if這類具有複雜結構(組合結構)的語句被稱為複合語句,其中包含一些部分,有些部分本身也是語句。在if語句兩個段的語句組裡可以出現一個或多個任意的語句,包括if語句本身。這說明if語句的結構具有遞歸性,其中一些部分可具有與整體相同的結構,整個結構可以任意複雜。如果某語句組裡隻有一個語句,python允許把它直接寫在該段的頭部之後,但人們不倡導這種寫法。

為使程式清晰易讀,python語言對if這類組合結構的寫法有嚴格要求,包括兩方面:①處于同一層的不同成分必須互相對齊,②下一層的成分需要統一倒退。如果一個子部分包含了順序的多個語句,這些成分語句也必須互相對齊。

以if語句為例,如果它包含else段,if和else兩個關鍵字必須在同一列上對齊(左對齊)。進而,兩個語句塊裡的成分語句需要統一地倒退并互相對齊。上面示例程式裡的if語句及其成分都正确對齊了,這是必須的。這些要求是python語言的特殊規定,多數語言沒有這種要求。python采用強制性的格式規定,是為了使程式裡的語句結構清晰,具有較好的可讀性。

初看起來貫徹上面的規定似乎很麻煩。但如果用idle編輯器(或其他專門針對python的編輯器),保證格式的工作都很簡單。idle能自動對齊同一層的語句,對于if等組合結構,它也能自動确定内層結構的對齊位置(多增加幾個空格,可以自己設定。預設為4個字元,人們認為4個字元既足夠清晰,也不帶來大片空白,是比較好的設定)。此外,在idle編輯狀态下按tab鍵,idle會把輸入光标移到下一對齊位置(通過加入幾個空格);如果按backspace鍵,idle就會把輸入光标退到前一層對齊位置。做這兩種移動時,光标所在的行不變。應特别注意:在編寫python程式時,不要自己用空格鍵在一行開始加空格,應直接利用idle的預設對齊方式,既友善又不會出錯。

在編寫python程式時,應特别注意tab字元和空格不能混用,因為它們都看不見,不易識别。采用非專門用于python程式的編輯器程式設計式時,有可能出現這類錯誤,應該特别注意。程式裡出現對齊錯誤時,解釋器也看作文法錯,可以定位和報告。

if語句的擴充形式

程式裡也經常需要區分多種(兩種以上)不同情況,分别處理。顯然,這種需求可以用嵌套的if語句表示,即在一個if語句的語句組裡再寫if語句。python為常見情況提供了擴充的if語句形式,允許用一系列邏輯表達式來區分多種情況:

也就是說,在語句的if段之後可以包含任意多個elif段,每個段包含形式為“elif 表達式:”的頭部和一個語句塊體。最後是else段。在執行這種if語句時,解釋器先求值第一個表達式,如果其值為真就執行第一個語句組,然後整個if結束。如果第一個表達式的值是假,解釋器就轉去求值随後的elif段頭部的表達式,如果其值為真就執行該elif段的語句組,然後整個if結束。如果被求值表達式還是假,解釋器就繼續考慮下一個elif段,直到在某步求得表達式的值為真,轉去執行相應語句組。遇到所有表達式都是假的情況,解釋器将執行else段的語句組(如果有這個段)。注意,無論有多少個elif段(及最後的else段),在if語句執行中至多執行一個段裡的語句塊。

下面将看到這種擴充結構的使用。顯然,檢查輸入隻是邏輯判斷與條件語句的一種用途,正常計算中也經常需要分情況處理,這時就應該用條件語句。

2.7.3 程式設計執行個體

現在考慮幾個程式設計執行個體。

求二次函數的根

計算二次函數的根是一項很常見的計算:給定二次函數的三個系數,根據公式算出函數的根。這裡需要根據判别式的值區分三種情況,可能存在兩個實根,或者存在一個重根,或者是無實根(存在一對共轭的複根)。下面隻考慮實根的情況。

完成這一計算,應該先求出判别式的值,然後根據這個值分情況處理。根據二次函數的求根公式,不難寫出下面的程式:

這裡增加了第一個列印語句,告知使用者這是什麼程式,是一種提示。程式裡使用了擴充的if語句,分三種情況分别處理。還需要注意的是除以2a的寫法。

讀者在前面已經看了不少程式執行情況。為了減少頁面占用,今後除一些特殊情況外,書中将不再給出程式執行的情況。請讀者自己運作程式檢視效果。

簡單總計

買一種貨品需要從單價和數量算出總貨款。考慮寫一個程式完成這一簡單計算。顯然,計算中也需要輸入資料。不難寫出下面程式,其中做了必要的檢查:

在這個程式裡可以看到字元串的使用,以及如何結合使用字元串(字面量和儲存在變量的字元串)和數值,生成較為複雜的輸出形式。

當然,也可以利用字元串操作生成出同樣的字元串,令print輸出構造好的串。如果隻是為了産生輸出,僅利用print輸出多個參數值的功能就能滿足需要,像上面這樣直接輸出可能更友善。作為練習,請讀者修改程式,利用字元串操作構造出同樣的或更符合自己想法的字元串,而後調用print輸出該串。