官术网_书友最值得收藏!

1.4 程序控制

當聲明一個變量時,用表達式來創建與處理對象,如果再添加一些邏輯控制,就形成了語句。也可以說,語句包含了表達式,所以,語句是Python程序構成最基本的一個基礎設施。

1.4.1 Python賦值語句

學會 Python 中的賦值語句,其他語句的學習就變得容易了。學習 Python 賦值語句主要是掌握和理解它的賦值邏輯。

1.賦值語句

Python中賦值語句的本質是創建一個對象的引用。主要有以下幾種賦值方式。

1)基本賦值方式

“a=5”:就相當于創建了一個變量a,指向內存中存儲的5這個對象。“a=5”就是一個賦值語句,執行賦值操作后,可以隨意打印或者顯示a的值。

2)理解賦值邏輯

通過一個圖來演示變量a、對象5在內存中存儲的情況。

這里以簡單的數值數據為例,以后可能會遇到結果更為復雜的數據,它的存儲機制可能會有所區別。

聲明變量的時候,最起碼有兩個部分,一個是用來存儲變量名稱的變量表,另一個是內存存儲區域[4,6]

當聲明“a=5”時,首先系統在內存區域開辟了一塊存儲空間,將數值 5 存儲起來,然后將變量 a 指向內存里存儲的對象 5,相當于在內存存儲區域里先有對象 5,然后再在變量表里出現一個“a”,并且指向 5,這個指向也可以稱為“引用”。賦值邏輯的理解如圖1-22所示。

圖1-22 理解賦值邏輯

圖1-22顯示了變量的類型與變量的名稱無關,即變量本身沒有類型約束,在聲明變量時不需要聲明變量名稱的類型,原因在于它的類型取決于它所關聯的對象。Python 的變量本身沒有類型,即a是沒有類型的,它的類型是跟5依附在一起的。

賦值語句的語法雖然簡單,但請仔細理解Python中的賦值邏輯。這種賦值邏輯影響著 Python 的方方面面,理解了賦值邏輯,就能更好地理解和編寫 Python 程序。如果你有 C 語言的編程經驗,便知道在 C 程序中變量是保存了一個值,而在 Python 中的變量是指向一個值。變量只作為一種引用關系存在,而不再擁有存儲功能。在Python中,每個數據都會占用一個內存空間,數據在Python中被稱為對象(Object)。

一個整數5是一個int型對象,一個'hello'是一個字符串對象,一個[1,2,3]是一個列表對象。

下面來更進一步理解賦值語句。

看下面的例子:

第一個賦值語句表示“a”指向 5 這個對象,第二個語句表示“a”指向“a+5”這個新的數據對象。可以理解為:

Python 把一切數據都看成“對象”。它為每個對象分配一個內存空間。一個對象被創建后,它的id(identity,意為“身份、標識”)就不再發生變化了。

在 Python 中,可以使用全局內置函數 id(obj)來獲得一個對象的 id,將其看作該對象在內存中的存儲地址。全局內置函數直接使用,不需要引用任何的包。

說明:變量a前后地址的變化說明變量是指向對象的!

一個對象被創建后,它不能被直接銷毀。因此,在上面的例子中,變量 a 首先指向了對象 5,然后繼續執行“a=a+5”,a+5 產生了一個新的對象 10。由于對象 5 不能被銷毀,則令 a 指向新的對象 10,而不是用對象 10 去覆蓋對象 5。在代碼執行完成后,內存中依然有對象5,也有對象10,只是此時變量a指向了新的對象10。

請大家通過上機測試來理解和掌握賦值邏輯。

如果沒有變量指向對象 5(無法引用它),Python 會使用垃圾回收機制來決定是否回收它(這是自動的,不需要程序編寫者操心)。

在Python內部有一個垃圾回收機制,垃圾回收機制檢測到如果在特定時間內沒有變量引用某一個對象,這個對象將被回收,釋放它所占用的資源。在Python內部有一個引用計數器,垃圾回收機制根據引用計數器來判斷對象是否有引用,以此來決定是否自動釋放該對象所占用的資源。垃圾回收機制的目標是Python中未被引用的對象,它是根據引用計數器得到的一個結果來進行推斷的。

這一點的理解也很重要,在今后講到列表等數據類型的時候,我們會再次看到正確理解變量指向對象的重要性。

一個舊的對象不會被覆蓋,因舊的對象交互而新產生的數據會放在新的對象中。也就是說每個對象是一個獨立的個體,每個對象都有自己的“主權”。因此,兩個對象的交互可以產生一個新的對象,而不會對原對象產生影響。在大型程序中,各個對象之間的交互錯綜復雜,這種獨立性使得這些交互足夠安全。

接下來考慮另外一個情況——“共享引用”。“共享引用”跟存儲有關。先來了解Python的動態特性。

以上兩行代碼說明了Python的動態特性。接下來介紹Python的“共享引用”。

以上測試結果證明了 y 和 z 都指向了內存中的同一個對象'Tom',可以通過圖 1-23來理解“共享引用”。

圖1-23 共享引用

所謂“共享引用”指的是多個變量引用同一對象,同一對象通過id檢查的內存地址相同。接下來再看一個例子。

注意:判斷相等其實有兩種意義,一是通過表達式“a==b”判斷a和b存儲的字面值是否相等,即它們是否都是 50;二是通過調用函數 id 來檢查 a 和 b 是否指向了同一對象。

在實際開發過程中,判斷兩個變量是否指向同一對象,即判斷它們的地址是否相同時,除了用函數id來檢測,也可以用操作符“is”來判斷。如:

“==”判斷的是字面值是否相等,而操作符“is”判斷的是地址是否相同。請注意加以區分。

以上以逗號隔開完成了對多個變量的賦值操作,它其實就是一個 tuple 元組。后面在學習元組時再來詳細介紹它的原理。

4)多目標賦值

多目標賦值是將同一個值賦給多個變量的一種賦值方式。

5)增強賦值或參數化賦值

有時候希望將某個變量的值在它本身原有值的基礎上做一個操作之后再重新賦值給它,以替換它原有的值。

【例1-1】 交換兩個變量的值。

在其他語言里,比如 Java、C、C++等都至少需要 3 行以上的代碼才能完成兩個變量值的交換,而在Python中只需要一行代碼即可將兩個變量的值交換。

在介紹 Python 的其他語句之前,先看一下 Python 流程控制中的順序執行及基本的輸入輸出。

順序執行是流程控制中默認的代碼執行方式,比較簡單。其基本原理是:代碼的執行順序和程序代碼的編寫順序是一致的。

【例1-2】 編程輸出一個學生數學、英語、物理3門課程的成績。

程序執行順序與編寫順序一致。

以上程序中的數據是在程序中固定的,但有時候可能需要在程序的運行過程中,由編程人員或軟件使用人員向程序輸入一些數據,這就要用到輸入函數。

2.input()函數

控制臺上的輸入是通過全局函數 input()來實現的,input()函數接收用戶從控制臺上輸入的信息,默認類型為str字符類型,根據需要可以把它轉換為特定的數據類型。第2章會詳細介紹各種數據類型。

如果想在用戶輸入數據的時候給用戶一些提示,可以在 input()函數中傳入一個含提示信息的參數!

【例 1-3】 假設希望在程序運行過程中輸入學生的成績,即將寫死的數據改為由控制臺操作人員動態輸入,則相應的程序可以修改為:

說明:89、95、78三個數值是運行程序后用戶從鍵盤輸入的數據。

3.eval()函數

eval()函數將 str 字符型數據當作有效的表達式來求值并返回計算結果。簡單來說,就是將字符串左右兩端的引號去除。

【例1-4】 在上例的基礎上計算3門課程的平均分。

說明:89、98、78三個數值是運行程序后用戶從鍵盤輸入的數據。

平均成績的輸出是通過print()函數來完成的。

4.print()函數

這里 print()函數只是簡單地輸出一個對象或變量的值,事實上 print()函數還有一些常用的參數,在實際開發工作中使用起來非常靈活。

如果希望用一行特殊的字符來對前后行的輸出內容進行分隔,如用 20 個“=”來分隔前后兩行輸出的內容,可以用“print("="*20)”的方式來達成目標。

1)多個變量在一行輸出,默認用空格進行分隔

將逗號分隔的多個內容輸出在一行上,分隔符是空格。

2)多個變量在一行輸出,改變它們之間的分隔符

如果希望輸出的內容之間用其他的分隔符進行分隔,則可以寫為

其實這里可以用任意字符作為分隔符,即print()函數可以手動指定分隔符。

3)多行print()函數輸出在一行上

在 print()函數的參數表中,有一個指定終止符號的參數“end”,默認情況下是換行符,即“end='\n'”。因此,可以通過指定終止符把多個 print 語句的輸出內容輸出到一行上。

print()函數默認的分隔符是一個空格,終止符號是一個換行符“'\n'”。了解以上內容后,在實際開發中會大大提高輸出的靈活性。

5.數字的格式化輸出

通過格式化字符串來指定輸出數字的格式或位數。

1)輸出指定位數的小數

在格式化輸出中,花括號里的“:”表示對在當前位置出現的值進行格式化處理,“.2f”表示對后面的值以浮點型來輸出,但只保留2位小數,第三位進行四舍五入。

2)輸出千位分隔符

如果想讓輸出的值加上“,”千位分隔符,可以使用如下的形式:

3)輸出固定寬度的數值

若想指定整體數字輸出的寬度,則形式如下:

說明:“{:12,.2f}”中的“12”表示總的寬度,默認右對齊,不夠位數,前面補空格;“,”表示千分位分隔符;“.2f”表示保留2位小數。

因為有時需要在控制臺上輸出多行內容,每行又有多列,但每行有長有短,若希望排版更整齊一些,此時就可以使用這種方式。

print()函數更多的使用方式,請通過help(print)命令進行查閱。

1.4.2 順序結構

順序結構是一個程序中最為簡單也最為基本的結構,其執行順序按照代碼的排列順序自上而下地執行。如交換兩個變量的值:

這里,要正確理解語句“a,b=b,a”。系統實際上是把右邊的兩個變量當作元組(b,a)來進行賦值,具體來說,就相當于執行了以下三步操作:

(1)temp=(b,a),即把元組(b,a)賦值給一個臨時變量temp;

(2)a=temp[0],即把temp的第1個元素即b的值取出來賦值給變量a;

(3)b=temp[1],即把temp的第2個元素即a的值取出來賦值給變量b。

以上操作步驟的執行可以在第2章學習了元組數據類型后再來理解。

1.4.3 選擇結構

有時候我們希望能根據條件有所選擇地執行程序。

選擇結構的基本結構可以抽象為:

如果條件成立,則執行語句塊1的操作,然后執行if語句之后的操作;如果條件不成立,則執行語句塊2的操作,然后再執行if語句之后的操作。

【例1-5】 根據輸入的數是否大于0輸出不同的提示信息。

運行程序后,如果輸入的是數值3,則得到以下的輸出結果:

運行程序后,如果輸入的是數值-6,則得到的輸出結果如下:

1.條件表達式

條件表達式是指由運算符(算術運算符請見表1-1、關系運算符請見表1-2、邏輯運算符請見表1-3)將常量、變量和函數聯系起來的有意義的式子。

表1-1 常用的算術運算符

表1-2 關系運算符

表1-3 邏輯運算符

條件表達式只有True或False兩個值,因此,條件表達式的值應該為布爾類型。所有值為布爾類型的數據都可以作為條件表達式出現在選擇結構中。布爾類型在第 2 章數據類型中會詳細介紹。

在此處,大家只需要記住:True的值為1,False的值為0。但是當作為條件來進行判斷時,非0即為真(True),0即為假(False)。

說明:0表示假,條件不成立,因此,不執行print()函數,沒有信息輸出!

2.單分支結構

單分支結構是選擇結構中最為簡單的一種形式,其中,用冒號(:)表示語句塊的開始。其語法格式為:

當條件表達式為真時,則執行語句塊1,否則不執行。

3.二分支結構

二分支結構是在單分支結構上,補充當條件表達式不成立時的情況,其語法格式為:

當條件表達式值為True時,執行語句塊1;否則,執行語句塊2。

由此可見,語句1不會執行,而只會執行條件表達式不成立所對應的語句。Python中二分支結構還有一種更為簡潔的語法格式:

作用:如果條件成立,結果為表達式1的值,否則為表達式2的值。

4.多分支結構

當處理多個選擇情況時,通過多個if else語句嵌套太過麻煩,Python提供了多分支情況下的處理方式,其基本語法格式為:

其中,elif是else if的縮寫。

【例1-6】 某淘寶店的商品在進行打折促銷,購買1件商品不打折,購買5件及以上時打8折,購買8件及以上時打7折,購買10件及以上時打5折,購買15件及以上時打3折。每件商品單價3元,假設顧客購買的商品數量通過input()函數輸入,編程計算該顧客所需支付的總價。

運行以上程序后,根據輸入數據的不同會得到不同的結果,如上。更多情況請自行測試。

1.4.4 循環結構

順序結構和選擇結構已經可以解決大多數問題,但是當需要對一大堆數據進行同樣的操作時,此時就要用到循環結構來解決這個問題。

1.遍歷循環(迭代語句)

Python中最典型的迭代語句是for-in遍歷循環,也稱為遍歷語句。

Python 中的 for-in 遍歷循環可以遍歷任何序列的項目,如一個列表或一個字符串。第2章會介紹序列類型(包含可變序列和不可變序列)。

遍歷循環的語法格式為:

該遍歷循環不是計數循環,循環變量依次從迭代對象(遍歷結構)中獲取元素,對象(結構)中的元素獲取完了,循環就結束了。循環的次數由迭代對象中元素的個數來決定。對獲取的每個元素都要執行循環體里的操作,除非遇到 break 或 continue 語句。可以在第2章介紹序列后再來看它的更多應用。

【例1-7】 輸出1~5的值,代碼如下。

代碼中,range()函數返回一個range的可迭代對象。第2章將會介紹range()函數。

【例1-8】 理解不是計數循環的含義。對比上一個例子中輸出的結果。

上面的程序雖然在循環體中改變了變量 i 的值,但輸出結果并沒有變化。原因是:該遍歷循環執行時變量依次從迭代對象“range(1,6)”中取出元素,第 1 次取第 1 個元素,第2次循環時取第2個元素,……雖然在第1次循環時,循環體中執行“i=i+3”使得i的值為4,其實,是i指向對象4(請參考1.3.1節的內容認真理解這句話);進入第2次循環時,變量i重新獲得迭代對象“range(1,6)”的第2個元素2,即變量i指向對象2,所以第2次循環輸出的i值還是2,如此繼續,直到迭代對象“range(1,6)”中的元素被遍歷完,結束循環。關于迭代對象“range(1,6)”更詳細的理解請學習第2章。

如果剛從其他編程語言轉到 Python,這是最容易出錯的地方。請注意理解 Python中的for-in循環叫遍歷循環或叫迭代語句的含義,所以,通常稱for-in遍歷循環或for-in迭代語句,一般不簡單地稱為 for-in 循環,以避免引起理解上的混淆。第 2 章序列類型學習之后,我們會看到for-in遍歷循環的更多用處。

2.while循環

for-in 遍歷循環是當遍歷完迭代對象后就結束循環,對于它的循環次數實際上是已知的,如:

雖然已知它的循環次數,但此時不能這樣來使用:

出錯信息表明“len(range(1,6))”是一個整數而不是一個可迭代序列,“for-in”關鍵字“in”后一定要跟一個可迭代對象。

所以,當循環次數可以確定時,通常會采用 for-in 遍歷循環,利用 range 函數來控制循環的次數。當循環次數不確定時,通常采用 while 循環,通過 while 語句的條件表達式來確定循環是否還要繼續。

while循環的語法格式如下:

只要條件表達式的值為真,就要執行循環體里的操作,直到條件為假退出循環為止。

【例1-9】 求和。計算sum=1+2+3+…+10。

由于最后一次執行循環體里的操作使得 i 的值大于 10,導致條件不成立,退出了循環,因此,退出循環后輸出的i值為11。

3.continue語句與break語句

continue語句與break語句可以用在for-in遍歷循環和while循環中,一般與選擇結構配合使用,二者的區別在于 continue 語句僅結束本次循環,即跳過本次循環中循環體里尚未執行的操作,但不跳出循環本身。break 語句則是結束整個循環(如果是嵌套的循環,它只跳出最內層的循環)。以下用實例說明二者的區別。

【例1-10】 計算1~5的偶數之和。

以上程序完成了 1~5 偶數相加的操作。當 i 的值為奇數時,條件“i%2!=0”成立,執行continue語句,跳過語句“sum+=i”。因為continue語句的作用是當流程執行到continue語句時就結束本次循環,即不執行“sum+=i”,而直接進入下一次循環。所以,最終求得的是2+4的結果。

將以上程序中的 continue 語句修改為 break 語句,其他代碼行都不變,觀察輸出的結果。

程序執行到i為3時,條件表達式“i%2!=0”的值為真,執行if中的break語句,而break語句的作用是結束整個循環,即退出循環直接執行循環外的print(sum)語句。所以,此時只加了一個數2,得到“sum=2”的結果。

4.for-in-else和while-else結構

for-in遍歷循環和while循環語句都存在一個帶else分支的擴展用法,語法格式為:

else 分支中的語句塊只在循環正常退出的情況下執行,即 for-in 遍歷循環中的變量遍歷完迭代對象中的所有元素,才執行 else 分支中的語句塊。while 循環是由于條件不成立而退出循環的,不是因為 break 或 return(函數返回中用到的保留字)提前退出循環才執行else分支中的語句塊。continue語句對else沒有影響。

【例1-11】 對比下面的程序,理解帶else分支的for-in遍歷循環的執行情況。

不論循環體里執行了什么操作,只要循環體里沒有執行 break 或 return,退出循環之后都要執行else分支中的語句,所以最后的輸出結果如上所示。

【例1-12】 for-in-else結構中,循環體里包含continue語句的執行情況分析。

說明:循環體里雖然有continue語句,但不影響else分支的執行。

【例1-13】 for-in-else結構中,循環體里包含break語句的執行情況分析。

說明:循環體中的 break 語句將會影響 else 分支的執行,只要執行了這個 break 語句,程序的流程就不會執行else分支!

以上實例說明循環語句中 else 分支的語句塊只在正常結束循環后才執行,而如果是因為break或return退出的循環,都不會執行else分支中的語句,這可以理解為else分支是對正常結束循環的一種獎勵。

5.嵌套循環

無論是 for-in 遍歷循環還是 while 循環,其循環體內的語句本身又可以是一個循環語句,這樣就構成了嵌套循環。具體的例子在第2章介紹序列數據類型后我們再來分析。

6.Python語法

Python的語法相較于常見的編程語言有一些特殊,因為它是強制縮進的。

語法:強制縮進要求必須是 4 個空格,這在上面的代碼中已經看到了。如果有嵌套的代碼塊,也是通過繼續縮進4個空格來實現的。

【例1-14】 理解代碼縮進體現代碼的邏輯。

注意:代碼行的縮進是必需的!

對于初學者,如果想詳盡了解 Python 編程規范,可以搜索“Python 增強標準協定PEP8 標準[7]”,它針對代碼的編排、文檔的編輯及空格的使用,包括注釋等都做了非常詳細的說明。有些是強制的,有些是非強制的。請大家通過搜索引擎進行搜索。

主站蜘蛛池模板: 洛南县| 永靖县| 嘉义市| 南漳县| 宜宾县| 开平市| 万山特区| 哈密市| 秦皇岛市| 临颍县| 新蔡县| 阳山县| 宾川县| 左贡县| 麟游县| 积石山| 凤山市| 巴青县| 湘乡市| 仙桃市| 余江县| 宁都县| 天镇县| 克东县| 秭归县| 双峰县| 蒙山县| 牟定县| 龙泉市| 新巴尔虎右旗| 永登县| 德清县| 南昌市| 宜阳县| 宁津县| 宁德市| 乌兰县| 博白县| 鹤庆县| 永平县| 徐水县|