第一篇 Python語言基礎
第3章 Python的控制語句
3.1 結構化程式設計
3.2 條件判斷語句
條件陳述式是指根據條件運算式的不同計算結果,使程式流轉至不同的代碼塊。Python中的條件陳述式有——if語句、if else語句。
3.2.1 if條件陳述式
if語句用於檢測某個條件是否成立。如果成立,則執行if語句內的程式;否則跳過if語句,執行後面的內容。if語句的格式如下。
01
if(運算式):
02
語句1
03
else:
04 語句2
if語句的執行過程如下:如果運算式的布林值為真,則執行語句1;否則,執行語句2。其中的else子句可以省略,運算式兩側的括弧也可以省略。
在講解if語句之前,先介紹一下Python中的控制台輸入函數。C語言中使用scanf()和getchar()捕獲使用者輸入,而Java語言的System.in包提供了控制台輸入的方法。Python也提供了類似功能的函數:input()捕獲用戶的原始輸入並將其轉為字串。input()函數的聲明如下。
input([prompt]) -> string
參數prompt是控制台中輸出的提示文字,提示使用者輸入,返回值為字串。如果輸入的是數位,返回的還是字串,使用前需要調用int()轉換一下。下面這段代碼說明了字串和數位類型的轉換。
01
x = input("x:")
02
x = int(x)
03
x = x + 1
如果不調用int()把字串轉換為數位,而直接計算運算式x=x+1,將提示如下錯誤。
TypeError: Can't convert 'int' object to
str implicitly
下面這段代碼演示了if語句的執行流程。
01
# 執行if語句內的程式
02
a = input("a:")
03
a = int(a)
04
b = input("b:")
05
b = int(b)
06
if(a > b):
07 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語句,執行後面的內容。
01
# 跳過if語句
02
a = input("a:")
03
a = int(a)
04
b = input("b:")
05
b = int(b)
06
if(a > b):
07 print (a, " > ", b)
08
print (a, " < ", b)
【代碼說明】
·第6行代碼中變數a的值小於變數b的值,因此,程式跳轉執行第6行代碼。
·第8行代碼,假設a=1、b=2。輸出結果:1<2
上面的代碼可以改寫成if
else結構的語句。
01
# if else語句
02
a = input("a:")
03
a = int(a)
04
b = input("b:")
05
b = int(b)
06
if(a > b):
07 print (a, " > ", b)
08
else:
09 print (a, " < ", b)
【代碼說明】
·第6行代碼中變數a的值小於變數b的值。因此,程式跳轉到else子句。
·第9行代碼,假設a=1、b=2。輸出結果:1<2
注意 else子句後需要加一個冒號,使Python解譯器能識別出else子句對應的代碼塊。Java程式師可能會不習慣這種語法,往往會忽略else子句後的冒號。在Python2中還有raw_input()函數用於接收使用者輸入,功能與Python3的input()相同。而Python2中的input()接收的值不轉換為字串類型,而是保留原始類型,在Python3中已經去除。
3.2.2 if…elif…else判斷語句
if…elif…else語句是對if…else…語句的補充。當程式的條件分支很多時,可以使用這種語句。if…elif…else語句相當於C、Java中的if…elseif…else語句。該語句的格式如下。
01
if(運算式1): 語句1
02
elif(運算式2): 語句2
03
…
04
elif(運算式n): 語句n
05
else: 語句m
if…elif…else語句的執行過程:首先判讀運算式1的值是否為真。如果為真,則執行語句1。否則,程式流轉到elif子句,判斷運算式2的值是否為真。如果運算式2的值為真,則執行語句2。否則,程式進入下面一個elif子句,依次類推。如果所有的運算式都不成立,則程式執行else子句的代碼。其中的else子句可以省略,運算式兩側的括弧也可以省略。
下面這段代碼通過判斷學生的分數,確定學生成績的等級。
01
# if elif else語句
02
score = float( input("score:")) # 接受用戶輸入並轉換為float類型,當輸入的為小數時,使用int轉換會報錯
03
if 90 <= score <= 100:
04 print("A")
05
elif 80 <= score < 90:
06 print("B")
07
elif 60 <= score < 80:
08 print("C")
09
else:
10 print("D")
【代碼說明】
·第2行代碼定義了一個變數score,假設輸入的值為70。這個變數表示學生的分數。接收用戶輸入並轉換為float類型。
·第3行代碼,分數大於等於90並且小於等於100,則等級評定為“A”。
·第5行代碼,分數大於等於80並且小於90,則等級評定為“B”。
·第7行代碼,分數大於等於60並且小於80,則等級評定為“C”。此時條件運算式成立,程式流轉到第8行。輸出結果為C。
·第9行代碼,當前面的條件運算式都不成立時,程式流轉到else子句。
3.2.3 if語句也可以嵌套
if語句的嵌套是指在if語句中可以包含一個或多個if語句。嵌套的格式如下所示。
01
If(運算式1):
02 if(運算式2): 語句1
03 elif(運算式3): 語句2
04 …
05
else: 語句3
06
elif(運算式n):
07 …
08
else:
09
…
下面這個程式是一個嵌套的條件陳述式。如果x的值大於0,則y的值等於1;如果x的值等於0,則y的值等於0;如果x的值小於0,則y的值等於-1。
01
x = -1
02
y = 99
03
if(x >= 0):
04 if(x > 0): #嵌套的if語句
05 y = 1
06 else:
07
y = 0
08
else:
09 y = -1
10
print ("y =", y)
【代碼說明】
·第2行代碼定義了一個變數y。為了不和最終可能的輸出結果1、0、-1重複,設置其初始值為99。
·第3行代碼判斷變數x的值。如果大於等於0,則執行下面嵌套的if語句。
·第4行代碼,判讀x的值是否大於0。如果大於0,則執行第5行代碼;否則執行第7行代碼。
·第8行代碼,如果變數x的值小於0,則執行第9行代碼。
·第9行代碼,由於變數x的值為-1,因此y的值等於-1。
·第10行代碼的輸出結果為-1。
嵌套語句可以組合出很多寫法,但是要注意把所有的分支情況都考慮到。下面的這種寫法是錯誤的。
01
# 錯誤的嵌套語句
02
x = -1
03
y = 99
04
if(x != 0): # 如果x不等於0
05 if(x > 0): #嵌套的if語句
06 y = 1
07
else:
08 y = 0
09
print ("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。
注意 編寫條件陳述式時,應該盡可能避免使用嵌套語句。嵌套語句不便於閱讀,而且可能會忽略一些可能性。
3.2.4 switch語句的替代方案
switch語句用於編寫多分支結構的程式,類似於if…elif…else語句。C語言中switch語句的結構如下所示。
01
switch(運算式) {
02 case 常量運算式1: 語句1
03 case 常量運算式2: 語句2
04 …
05 case 常量運算式n: 語句n
06 default: 語句m
07
}
switch語句表示的分支結構比if…elif…else語句更清晰,代碼可讀性更高。但是Python並沒有提供switch語句,Python可以通過字典實現switch語句的功能。
實現方法分為兩步。首先,定義一個字典。字典是由鍵值對組成的集合,字典的使用參見第4章的內容。其次,調用字典的get()獲取相應的運算式。
下面這段代碼通過算數運算的符號,獲取算數運算運算式。
01
# 使用字典實現switch語句
02
from __future__ import division
03
x = 1
04
y = 2
05
operator = "/"
06
result = { # 定義字典
07 "+" : x + y,
08 "-" : x - y,
09 "*" : x * y,
10 "/" : x / y
11
}
12
print (result.get(operator))
【代碼說明】
·第3、4行代碼定義了兩個運算元x、y。
·第5行代碼定義了操作符變數operator,該變數用於存放算術運算子。
·第6行代碼定義了一個字典result。該字典的key值由“+”、“-”、“*”、“/”四則運算符組成。value值由對應的算術運算式組成。
·第12行代碼調用get()方法,get()的參數即變數operator的值。由於operator的值為“/”,因此將執行除法運算。輸出結果:0.5。
另一種使用switch分支語句的方案是創建一個switch類,處理常式的流轉。這種實現方法比較複雜,涉及物件導向、for迴圈、中斷語句、遍歷等知識,實現步驟分為4步。
1)創建一個switch類,該類繼承自Python的祖先類object。調用構造函數__init__()初始化需要匹配的字串,並定義兩個成員變數value和fall。value用於存放需要匹配的字串,fall用於記錄是否匹配成功,初始值為False,表示匹配不成功。如果匹配成功,程式向後執行。
2)定義一個match()方法,該方法用於匹配case子句。這裡需要考慮3種情況。首先是匹配成功的情況,其次是匹配失敗的默認case子句,最後是case子句中沒有使用break中斷的情況。
3)重寫__iter__()方法,定義了該方法後才能使switch類用於迴圈語句中。__iter__()調用match()方法進行匹配。通過yield關鍵字,使函數可以在迴圈中反覆運算。此外,調用StopIteration異常中斷迴圈。Python中的迴圈都是通過異常StopIteration中斷的。這樣switch類就構造完成了。
4)編寫調用代碼,在for…in…迴圈中使用switch類。
下面這段代碼實現了switch語句的功能。
01
class switch(object):
02 def __init__(self, value): # 初始化需要匹配的值value
03 self.value = value
04 self.fall = False # 如果匹配到的case語句中沒有break,則fall為True
05
06 def __iter__(self):
07 yield self.match # 調用match方法 返回一個生成器
08 raise StopIteration # StopIteration 異常來判斷for迴圈是否結束
09
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
20
operator = "+"
21
x = 1
22
y = 2
23
for 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的結果。輸出結果為0.5。
·第26行代碼使用break語句中斷switch分支結構,程式流轉到檔的末尾。
本章3.3.3小節將繼續探討這個程式,當case子句中沒有break語句的執行情況。
注意 switch語句造成代碼不易維護,使原始檔案臃腫。物件導向的設計中常常對switch語句進行重構,把switch語句分解為若干個類。當然,對於分支流程簡單的switch,可以使用字典來實現。使用字典更容易管理switch,而switch類回到了C、Java的老路上,而且寫法更複雜了,不值得推薦。
3.3 迴圈語句
迴圈語句是指重複執行同一段代碼塊,通常用於遍歷集合或者累加計算。Python中的迴圈語句有while語句、for語句。
3.3.1 while迴圈
迴圈語句是程式設計中常用的語句之一。任何程式設計語言都有while迴圈,Python也不例外。while迴圈的格式如下所示。
01
while(運算式):
02 …
03
else:
04 …
while迴圈的執行過程:當迴圈運算式為真時,依次執行while中的語句。直到迴圈運算式的值為False,程式的流程轉到else語句。其中else子句可以省略,運算式兩側的括弧也可以省略。
注意 while迴圈中的else子句也屬於迴圈的一部分,最後一次迴圈結束後將執行else子句。
下面這段代碼演示了while迴圈的使用。程式首先要求輸入5個數位,然後依次輸出這5個數位。
01
# while迴圈
02
numbers = input("輸入幾個數字,用逗號分隔:").split(",")
03
print(numbers)
04
x = 0
05
while x < len(numbers): # 當x的值小於輸入字數的個數的時候,執行迴圈內容
06 print (numbers[x])
07 x += 1 # 一個迴圈結束時給x加1
【代碼說明】
·第2行代碼使用input()捕獲輸入。按照提示輸入5個數位,並用逗號分隔。input()根據輸入的逗號,生成一個列表。
·第3行代碼輸出清單numbers的內容。
·第4行代碼定義變數x的值為0。
·第5行代碼迴圈列表numbers。
·第6行代碼輸出列表中第x+1個數位的值。
·第7行代碼,每次迴圈使變數x增1。
下面這段代碼演示了else子句在while迴圈中的使用。當變數x的值大於0時,執行迴圈,否則輸出變數x的值。
01
# 帶else子句的while迴圈
02
x = float(input("輸入x的值:")) # 接收使用者輸入的數位並轉換為float類型
03
i = 0
04
while(x != 0): # Python3中不等於拋棄了<>,一律使用!=
05 if(x > 0):
06 x -= 1 # 如果x大於0則減1
07 else:
08 x += 1 # 如果x小於0則加1
09 i = i + 1
10 print( "第%d次迴圈:" %(i, x))
11
else:
12 print ("x等於0:", x)
【代碼說明】
·第2行代碼輸入變數x的值。
·第3行代碼定義變數i,變數i表示迴圈的次數。
·第4行代碼,給出迴圈條件x!=0。如果x不等於0,則執行第5行代碼;否則,執行else子句的內容。
·第5行代碼,判斷變數x的值是否大於0。
·第6行代碼,如果x的值大於0,則每次迴圈都減1。
·第7行代碼,判斷變數x的值是否小於0。
·第8行代碼,如果x的值小於0,則每次迴圈都加1。
·第9行代碼,每次迴圈使變數i的值加1。
·第11行代碼,迴圈結束,else子句輸出變數x的值。輸出結果(假設輸入數位為0):
x等於0:0
在使用迴圈語句時,應注意迴圈運算式的布林值,避免出現閉環。閉環是指迴圈條件永遠為真的迴圈。例如:
01
i = 1
02
while i > 0: # i永遠大於0
03 i = i + 1
04 print(i)
這段代碼就是一個閉環,變數i的值永遠都大於0。
3.3.2 for迴圈
for迴圈用於遍歷一個集合,依次訪問集合中的每個專案。for迴圈的格式如下所示。
01
for 變數 in 集合:
02 …
03
else:
04 …
for…in…迴圈的執行過程:每次迴圈從集合中取出一個值,並把該值賦值給變數。集合可以是元組、清單、字典等資料結構。其中else子句可以省略。
注意 for迴圈中的else子句也屬於迴圈的一部分,最後一次迴圈結束後將執行else子句。
for…in…迴圈通常與range()函數一起使用,range()返回一個列表,for…in…遍歷清單中的元素。range()函數的聲明如下:
class range(object)
range(stop) -> range object
range(start, stop[, step]) -> range
object
【代碼說明】 range()返回一個range物件,清單的元素值由3個參數決定;參數start表示列表開始的值,預設值為0;參數stop表示列表結束的值,該參數不可缺少;參數setp表示步長,每次遞增或遞減的值,預設值為1。
下面這段代碼遍歷range()生成的列表,過濾出正數、負數和0。
01
# for in語句
02
for x in range(-1, 2):
03 if x > 0:
04 print ("正數:",x)
05 elif x == 0 :
06 print ("零:",x)
07 else:
08 print ("負數:",x)
09
else:
10 print ("迴圈結束")
【代碼說明】
·第2行代碼遍歷range(-1,2)生成的列表。range(-1,2)返回的3個數字分別為-1、0、1。每次迴圈變數x的值依次為-1、0、1。
·第3行代碼判斷變數x的值是否大於0。
·第4行代碼輸出正數的值。輸出結果:正數:1。
·第5行代碼判斷變數x的值是否等於0。
·第6行代碼,輸出結果:零:0。
·第8行代碼,輸出負數的值。輸出結果:負數:-1。
·第9行代碼並沒有結束for迴圈,else子句執行後迴圈才結束。輸出結果:負數:-1。
在C、Java語言中,支援如下結構的for語句。
for(運算式1; 運算式2; 運算式3)
語句塊
Python不支持這樣的for迴圈。如果需要編寫類似功能的迴圈,可以使用while迴圈。例如:
01
x = 0
02
while x < 5:
03 print(x)
04 x = x + 2
while迴圈的寫法比較瑣碎,需要比較判斷。也可以使用for迴圈,借助range()函數來實現。例如:
01
for x in range(0, 5, 2):
02
print (x)
【代碼說明】 輸出的數字在[0,5]這個區間,不包括5。每次迴圈x的值加2。輸出結果:
0
2
4
這裡只用了兩行代碼即實現了傳統for迴圈。如果要用條件運算式作為迴圈的條件,可以構造range()函數來實現。
3.3.3 break和continue語句
break語句可以使程式跳出迴圈語句,從而執行循環體之外的程式,即break語句可以提前結束迴圈。例如,3.2.4小節類比switch分支結構使用了break語句。
01
operator = "+"
02
x = 1
03
y = 2
04
for case in switch(operator): # switch只能用於for in迴圈中
05 if case('+'):
06 print (x + y)
07 break
08 if case('-'):
09 print (x - y)
10 break
11 if case('*'):
12
print (x * y)
13 break
14 if case('/'):
15 print (x / y)
16 break
17 if case(): # 預設分支
18
print ("")
【代碼說明】 第7行代碼中使用了break。當變數operator的值為“+”,則執行運算式x+y,然後中斷switch分支結構,後面的case分支都不會執行。此時輸出結果為3。後面的break作用相同。當匹配到某個case後,程式將跳出switch。
如果第一個case不使用break子句,程式將輸出兩個值,分別是3和-1。因為輸出運算式x+y後,分支結構並沒有中斷,程式將流轉到下面一個case。然後繼續計算運算式x–y的值,遇到後面的break語句才退出分支結構。break語句在迴圈結構中也有類似的作用。下面這段代碼將從0到99中查找用戶輸入的值。
01
x = int(input("輸入x的值:"))
02
y = 0
03
for y in range(0, 100):
04 if x == y:
05 print ("找到數位:", x)
06 break
07
else:
08
print("沒有找到")
【代碼說明】
·第1行代碼捕獲用戶輸入的值,並把該值轉換為int類型後賦值給變數x。
·第2行代碼定義一個變數y,變數y用於暫存需要遍歷的清單的值。
·第3行代碼使用for…in…迴圈遍歷range(0,100)返回的列表。range(0,100)的返回值為0、1、2…99。
·第4行代碼判斷輸入的值是否等於列表中的值。如果條件成立,輸出查找到的數位,並立即退出迴圈。迴圈結束,後面的else子句將不會被執行。
·第7行代碼,當沒有找到輸入的值時,else子句後面的代碼將被執行。
注意 break語句不能運行在循環體或分支語句之外,否則,Python解譯器將提示如下錯誤。
SyntaxError: 'break' outside loop
continue語句也是用來跳出迴圈的語句,但是與break不同的是,continue不會跳出整個循環體,只是跳出當前的迴圈,然後繼續執行後面的迴圈。
01
x = 0
02
for i in [1,2,3,4,5]:
03 if x == i:
04 continue
05
x += i
06
print("x的值為", x)
【代碼說明】
·第1行代碼將x賦值為0。
·第2行代碼使用for...in...語句遍歷列表[1,2,3,4,5]。
·第3行代碼將x與i進行比較,如果x與值i相等則執行第4行的continue語句,停止當前迴圈,即不再執行第5行代碼,繼續執行下一個迴圈。
·第6行代碼列印出最終的結果,輸出為:12。
3.4 結構化程式示例
下面這段代碼實現了冒泡排序。
01
# 冒泡排序
02
def bubbleSort(numbers): # 冒泡演算法的實現
03 for j in range(len(numbers) - 1, -1,
-1):
04 for i in range(j):
05 if numbers[i] >
numbers[i+1]: # 把數值小的數字放到頂端
06 numbers[i], numbers[i+1]
= numbers[i+1], numbers[i]
07 print (numbers)
08
09
def main(): # 主函數
10 numbers = [23, 12, 9, 15, 6]
11 bubbleSort(numbers)
12
13
if __name__ == '__main__':
14 main()
【代碼說明】
·第2行代碼定義bubbleSort()實現冒泡排序。
·第3行代碼確定每趟迴圈的比較次數。
·第4行代碼迴圈比較相鄰的兩個元素。
·第5行代碼判斷相鄰兩個元素的大小。
·第6行代碼把數值較小的數排到前面。
·第7行代碼輸出每趟的比較結果。輸出結果:
[12, 23, 9, 15, 6]
[12, 9, 23, 15, 6]
[12, 9, 15, 23, 6]
[12, 9, 15, 6, 23]
[9, 12, 15, 6, 23]
[9, 12, 15, 6, 23]
[9, 12, 6, 15, 23]
[9, 12, 6, 15, 23]
[9, 6, 12, 15, 23]
[6, 9, 12, 15, 23]





0 留言:
發佈留言