導讀:條件語句是指根據條件表達式的不同計算結果,使程序流轉至不同的代碼塊。Python/ target=_blank class=infotextkey>Python中的條件語句有——if語句、if… else…語句。
作者:黃傳祿 張克強 趙越
來源:華章科技
01 if條件語句
if語句用于檢測某個條件是否成立。如果成立,則執行if語句內的程序;否則,跳過if語句,執行后面的內容。if語句的格式如下。
if(表達式):
語句1
else:
語句2
if語句的執行過程如下:如果表達式的布爾值為真,則執行語句1;否則,執行語句2。其中的else子句可以省略,表達式兩側的括號也可以省略。
在講解if語句之前,先介紹一下Python中的控制臺輸入函數。在C語言中,使用scanf()和getchar()捕獲用戶輸入,而JAVA語言的System.in包提供了控制臺輸入的方法。Python也提供了類似功能的函數——input(),用于捕獲用戶的原始輸入并將其轉為字符串。input()函數的聲明如下。
input([prompt]) -> string
參數prompt是控制臺中對于輸入的提示文字,提示用戶輸入,返回值為字符串。如果輸入的是數字,返回的還是字符串,那么使用前需要調用int()做一下字符串和數字類型的轉換。下面這段代碼說明了字符串和數字類型的轉換。
x = input("x:")
x = int(x)
x = x + 1
如果不調用int()把字符串轉換為數字,而直接計算表達式x = x + 1,將提示如下錯誤。
TypeError: Can't convert 'int' object to str implicitly
下面這段代碼演示了if語句的執行流程。
1# 執行if語句內的程序
2a = input("a:")
3a = int(a)
4b = input("b:")
5b = int(b)
6if(a > b):
7 print (a, " > ", b)
【代碼說明】
- 第2行代碼定義了變量a。
- 第3行將用戶輸入的a轉換為int類型。
- 第4行代碼定義了變量b。
- 第5行將用戶輸入的b轉換為int類型。
- 第6行代碼判斷變量a、b的大小。
- 對于第7行代碼,假設a=2、b=1,輸出結果:2>1。
如果不滿足if語句內的條件,程序將跳過if語句,執行后面的內容。
1# 跳過if語句
2a = input("a:")
3a = int(a)
4b = input("b:")
5b = int(b)
6if(a > b):
7 print (a, " > ", b)
8print (a, " < ", b)
【代碼說明】
- 假設a=1、b=2,第6行代碼中變量a的值小于變量b的值,因此,程序跳轉執行第8行代碼。
- 第8行代碼輸出結果:1<2。
【例3-1】把上面的代碼改寫成if… else…結構。
【例3-1.py】
1# if… else…語句
2a = input("a:")
3a = int(a)
4b = input("b:")
5b = int(b)
6if(a > b):
7 print (a, " > ", b)
8else:
9 print (a, " < ", b)
【代碼說明】
- 假設a=1、b=2,第6行代碼中變量a的值小于變量b的值。因此,程序跳轉到else子句。
- 第9行代碼輸出結果:1<2。
注意:else子句后需要加一個冒號,使Python解釋器能識別出else子句對應的代碼塊。Java程序員可能會不習慣這種語法,往往會忽略else子句后的冒號。在Python 2中還可用raw_input()函數接收用戶輸入,其功能與Python 3的input()相同。而Python 2中的input()接收的值不轉換為字符串類型,而是保留原始類型,它在Python 3中已經去除。
02 if…elif…else判斷語句
if…elif…else語句是對if…else…語句的補充。當程序的條件分支很多時,可以使用這種語句。if…elif…else語句相當于C、Java中的if…elseif…else語句。該語句的格式如下。
if(表達式1): 語句1
elif(表達式2): 語句2
…
elif(表達式n): 語句n
else: 語句m
if…elif…else語句的執行過程:首先判斷表達式1的值是否為真。如果為真,則執行語句1。否則,程序流轉到elif子句,判斷表達式2的值是否為真。如果表達式2的值為真,則執行語句2。否則,程序進入下面一個elif子句,以此類推。如果所有的表達式都不成立,則程序執行else子句的代碼。其中的else子句可以省略,表達式兩側的括號也可以省略。
下面【例3-2】中的這段代碼通過判斷學生的分數,確定學生成績的等級。
【例3-2.py】
1# if elif else語句
2score = float( input("score:")) # 接收用戶輸入并將其轉換為float類型,當輸入為小數時,使用int轉換會報錯
3if 90 <= score <= 100:
4 print("A")
5elif 80 <= score < 90:
6 print("B")
7elif 60 <= score < 80:
8 print("C")
9else:
10 print("D")
【代碼說明】
- 第2行代碼定義了一個變量score,假設輸入的值為70。這個變量表示學生的分數。接收用戶輸入并將其轉換為float類型。
- 第3行代碼,分數大于等于90并且小于等于100,則等級評定為“A”。
- 第5行代碼,分數大于等于80并且小于90,則等級評定為“B”。
- 第7行代碼,分數大于等于60并且小于80,則等級評定為“C”。此時條件表達式成立,程序流轉到第8行。輸出結果為C。
- 第9行代碼,當前面的條件表達式都不成立時,程序流轉到else子句。
03 if語句也可以嵌套
if語句的嵌套是指if語句中可以包含一個或多個if語句。嵌套的格式如下所示。
if(表達式1):
if(表達式2): 語句1
elif(表達式3): 語句2
…
else: 語句3
elif(表達式n):
…
else:
…
下面【例3-3】中的這段代碼是一個嵌套的條件語句。如果x的值大于0,則y的值等于1;如果x的值等于0,則y的值等于0;如果x的值小于0,則y的值等于-1。
【例3-3.py】
1x = -1
2y = 99
3if(x >= 0):
4 if(x > 0):#嵌套的if語句
5 y = 1
6 else:
7 y = 0
8else:
9 y = -1
10print ("y =", y)
【代碼說明】
- 第2行代碼定義了一個變量y。為了不和最終可能的輸出結果1、0、-1重復,設置y的初始值為99。
- 第3行代碼判斷變量x的值。如果x大于等于0,則執行下面嵌套的if語句。
- 第4行代碼,判讀x的值是否大于0。如果大于0,則執行第5行代碼;否則,執行第7行代碼。
- 第8行代碼,如果變量x的值小于0,則執行第9行代碼。
- 第9行代碼,由于變量x的值為-1,因此y的值等于-1。
- 第10行代碼的輸出結果為-1。
嵌套語句可以組合出很多寫法,但是要注意把所有的分支情況都考慮到。下面的這種寫法是錯誤的。
1# 錯誤的嵌套語句
2x = -1
3y = 99
4if(x != 0): # 如果x不等于0
5 if(x > 0): #嵌套的if語句
6 y = 1
7else:
8 y = 0
9print ("y =", y)
【代碼說明】
- 第4行代碼判斷變量x的值是否等于0。如果不等于0,則執行if語句下面的代碼塊;否則執行else子句的代碼。由于x的值等于-1,程序流轉到第5行。
- 第5行代碼判斷變量x的值是否大于0。如果大于0,則變量y的值設置為1。由于這里沒有考慮到變量x小于0的情況,所以程序直接跳轉到第9行。
- 第9行代碼,變量y的值并沒有被改變,程序的分支結構沒有考慮到x小于0的情況,所以最終輸出的不是期望中的結果。輸出結果為99。
注意:編寫條件語句時,應該盡可能避免使用嵌套語句。嵌套語句不便于閱讀,而且可能會忽略一些可能性。
04 switch語句的替代方案
switch語句用于編寫多分支結構的程序,類似于if…elif…else語句。C語言中switch語句的結構如下所示。
switch(表達式) {
case 常量表達式1: 語句1
case 常量表達式2: 語句2
…
case 常量表達式n: 語句n
default: 語句m
}
switch語句表示的分支結構比if…elif…else語句更清晰,代碼可讀性更高,但是Python并沒有提供switch語句,而是可以通過字典實現switch語句的功能。
實現方法分為兩步。首先,定義一個字典。字典是由鍵值對組成的集合。其次,調用字典的get()獲取相應的表達式。
下面【例3-4】中的這段代碼通過算術運算的符號,獲取算術運算表達式。
【例3-4.py】
1# 使用字典實現switch語句
2from __future__ import division# 導入division模塊
3x = 1
4y = 2
5operator = "/"
6result = { # 定義字典
7"+" : x + y,
8"-" : x - y,
9"*" : x * y,
10"/" : x / y
11}
12print (result.get(operator))
【代碼說明】
- 第3、4行代碼定義了兩個操作數x、y。
- 第5行代碼定義了操作符變量operator,該變量用于存放算術運算符。
- 第6行代碼定義了一個字典result。該字典的key值由“+”“-”“*”“/”四則運算符組成。value值由對應的算術表達式組成。
- 第12行代碼調用get()方法,get()的參數就是變量operator的值。由于operator的值為“/”,因此將執行除法運算。輸出結果為0.5。
另一種使用switch分支語句的方案是創建一個switch類,處理程序的流轉。這種實現方法比較復雜,涉及面向對象、for循環、中斷語句、遍歷等知識,實現步驟分為4步。
- 創建一個switch類,該類繼承自Python的祖先類object。調用構造函數__init__()初始化需要匹配的字符串,并定義兩個成員變量value和fall。value用于存放需要匹配的字符串。fall用于記錄是否匹配成功,初始值為False,表示匹配不成功。如果匹配成功,程序向后執行。
- 定義一個match()方法,該方法用于匹配case子句。這里需要考慮3種情況。首先是匹配成功的情況,其次是匹配失敗的默認case子句,最后是case子句中沒有使用break中斷的情況。
- 重寫__iter__()方法,定義了該方法后才能使switch類用于循環語句中。__iter__()調用match()方法進行匹配,通過yield關鍵字,使函數可以在循環中迭代。此外,調用異常StopIteration中斷循環。Python中的循環都是通過異常StopIteration中斷的。這樣switch類就構造完成了。
- 編寫調用代碼,在for…in…循環中使用switch類。
下面【例3-5】中的這段代碼實現了switch語句的功能。
【例3-5.py】
1class switch(object):# 定義switch類
2 def __init__(self, value):# 初始化需要匹配的值value
3 self.value = value
4 self.fall = False # 如果匹配到的case語句中沒有break,則fall為True
5
6 def __iter__(self):# 定義__iter__()方法
7 yield self.match # 調用match方法 返回一個生成器
8 raise StopIteration# 用StopIteration 異常來判斷for循環是否結束
9
10 def match(self, *args): # 模擬case子句的方法
11 if self.fall or not args: # 如果fall為True,則繼續執行下面的case子句
12 # 或case子句沒有匹配項,則流轉到默認分支
13 return True
14 elif self.value in args: # 匹配成功
15 self.fall = True
16 return True
17 else: # 匹配失敗
18 return False
19
20operator = "+"
21x = 1
22y = 2
23for case in switch(operator): # switch只能用于for... in...循環中
24 if case('+'):
25 print (x + y)
26 break
27 if case('-'):
28 print (x - y)
29 break
30 if case('*'):
31 print (x * y)
32 break
33 if case('/'):
34 print (x / y)
35 break
36 if case(): # 默認分支
37 print ""
【代碼說明】
- 第1行到第18行代碼定義了switch類,定義了__init__()、__iter__()、match()方法。
- 第23行代碼在for…in…循環中調用switch類,變量operator作為switch類的參數傳遞給構造函數。變量operator的值等于“+”,程序流轉到第24行。
- 第25行代碼輸出x + y的結果。輸出結果為3。
- 第26行代碼使用break語句中斷switch分支結構,程序流轉到文件的末尾。
注意:switch語句會造成代碼不易維護,使源文件臃腫。面向對象的設計中常常對switch語句進行重構,把switch語句分解為若干個類。當然,對于分支流程簡單的switch,可以使用字典來實現。使用字典更容易管理switch,而switch類回到了C、Java的老路上,而且寫法更復雜了,不值得推薦。
關于作者:黃傳祿,高級講師、管理軟件開發工程師、數據庫庫系統工程師、信息系統管理工程師。有10多年的一線教學經驗和高端培訓經驗,出版多部技術專著,獲得多個軟件著作權。
本文摘編自《零基礎學Python》(第2版),經出版方授權發布。