我要翻譯《Think Python》- 004 第二章 變數, 表示式和語句
PDF原始檔地址 : http://www.greenteapress.com/thinkpython/thinkpython.pdf
[自述:這一章內容不多,但是由於時間關係,翻譯完成這一章也花了我一週的時間,跟我預想的進度相比已經落後了,得加油了,要不然翻譯完整本書就要到猴年馬月了。目前離翻譯完成還有17章!!!]
第二章
變數, 表示式和語法
2.1 值和型別
值是程式工作的基本要素,如字串“Hello,World!”或數字1、2等等。 這些值屬於不同型別:2是一個整數,而“Hello,World!”是字串,之所以這麼命名,是因為它包含了一“串”字元。您/直譯器可以識別字符串,那是因為它是用一對引號括起來的。另外你如果不確定值的型別,直譯器的type函式可以告訴你。 毫無疑問,字串屬於str型別,整數是int型別。 >>> type('Hello, World!') <type 'str'> >>> type(17) <type 'int'>
需要注意的是,有小數點的數字稱之為float型,即“浮點”格式表示的數字。
>>> type(3.2) <type 'float'>
那如何區分‘17’和‘3.2’這樣的值呢?它們看起來像數字,但是它們像字串一樣被引號括起來了。 >>> type('17') <type 'str'> >>> type('3.2') <type 'str'> 因此,它們是字串。 當你輸入一個大整數,你可能會用千分號隔開來表示數字1,000,000,這在Python裡面是非法的,但是在實際應用中卻是合法的。 >>> 1,000,000 (1, 0, 0) 這當然不是我們所期望的結果!Python把千分號隔開的整數1,000,000解釋為一個整數序列。這是本書的第一個語義錯誤的例子:程式碼執行沒有產生錯誤,但結果卻是“不對”的。
2.2 變數
程式語言最強大的特性之一就是變數賦值的能力,變數即值引用。 用賦值語句建立變數並給變數賦值: >>> message = 'And now for something completely different' >>> n = 17 >>> pi = 3.1415926535897932 以上3條賦值語句,第一個建立一個message新變數並賦值了一個字串,第二個把n賦值為整數17,第三個把π的近似值賦值給變數pi。 我們在紙上演示給變數賦值的時候,通常是先寫下變數名,然後用一個箭頭指向變數的值,這種型別的圖例我們稱之為狀態圖,因為狀態圖可以標示每個變數的狀態。上面例子的狀態圖如圖2.1所示。
圖2.1
變數型別即值引用型別。 >>> type(message)
<type 'str'> >>> type(n)
<type 'int'> >>> type(pi)
<type 'float'>
2.3 變數名和關鍵字
程式設計師通常會選擇有具體含義的名字來給變數命名——用來記錄變數的作用。 變數名的長度沒有限制,可以包含數字和字母,但是必須以字母開頭,推薦首字母小寫,當然首字母大寫也是合法的變數名(後面你會明白其原因)。 定義變數名也可以使用下劃線“_”,通常用在有多個單詞的變數名,例如my_name、airspeed_of_unladen_swallow等。 如果你定義一個非法的變數名,你將會得到一個語法錯誤: >>> 76trombones = 'big parade' SyntaxError: invalid syntax >>> [email protected] = 1000000 SyntaxError: invalid syntax >>> class = 'Advanced Theoretical Zymurgy' SyntaxError: invalid syntax 變數名 76trombones 不是以字母開頭,而 [email protected] 則包含了非法字元“@”,但是class為什麼也是錯誤的呢?那是因為class 是Python的一個關鍵字。因為直譯器運用關鍵字來識別程式結構,因此關鍵字是不能用來作為變數名使用的。 Python 2版本有31個關鍵字: and del from not while as elif global or with assert else if pass yield break except import print class exec in raise continue finally is return def for lambda try 而在Python 3版本中 exec 不再是關鍵字,但是多了一個nonlocal 關鍵字。 因此,請牢記這些關鍵字,當直譯器報變數名錯誤的時候你可以檢查變數名是否跟關鍵字重複了。
2.4 運算子和運算
像表示加法和乘法的運算子是特殊字元,將運算子應用到計算中叫做運算。
運算子+,-,*,/和**分別表示加法,減法,乘法,除法和冪,用法示例如下: 20+32 hour-1 hour*60+minute minute/60 5**2 (5+9)*(15-7)
在其它一些程式語言中,^表示異或運算,但是在Python中用XOR來表示異或位運算。本書不會討論位運算,如果你對此感興趣,請參考與位運算相關的連結:http://wiki.python.org/moin/BitwiseOperators 在Python2版本中,除法運算可能不像你想象的那樣: >>> minute = 59 >>> minute/60 0 例子中minute的值為59,在傳統算術中59除以60的結果是0.98333,而並不是0.而造成這種差異的原因是Python在執行的時候是向下取整數的,當兩個數都是整數的時候,結果也是整數。因此向下取整數就會把小數部分去掉了,因此本例計算結果就是0了。 在Python3版本中,這個除法運算的結果就是一個浮點數。而新的運算子 // 則表示向下取整數。 >>> minute/60.0 0.98333333333333328
2.5 表示式和語句
一個表示式是值、變數和運算子的組合,值和變數本身都被認為是表示式,因此下面這些表示式都是合法的(假設變數x已經被賦值):
17 x x + 17
語句是指Python直譯器可以執行的程式碼單元,我們可以看到兩種語句:列印和賦值。從技術上講表示式也是語句,只是把它們區分開來理解起來可能會顯得簡單一些,它們之間最大的差別在於:表示式有值,而語句則沒有。
2.6 互動模式和指令碼模式
使用解釋型語言有一個好處,就是把程式碼儲存為指令碼之前,你可以通過互動式的方式測試程式碼,但是互動模式和指令碼模式之間的差異依然容易被混淆。 例如,你當你把Python當成一個計算器使用,你可能輸入: >>> miles = 26.2 >>> miles * 1.61 42.182 第一行賦值給變數miles,但是卻看不到效果,第二行是一個表示式,所以直譯器計算並顯示了結果。由此我們得到了馬拉松全程長度為大約42公里。 但是你要是把程式碼寫在腳本里並且執行指令碼,你根本看不到輸出結果。在指令碼模式中,表示式本身並不可見,而Python實際上已經對錶達式進行了計算,你只有這樣輸入才會看到輸出結果: miles = 26.2 print miles * 1.61 最初你可能對直譯器的這種行為感到疑惑。 通常情況下,指令碼包含一系列的語句,如果輸出程式碼超過一行以上,那麼執行指令碼的結果將會一次性的顯示出來。 例如,指令碼如下: print 1 x = 2 print x 輸出結果如下: 1 2 賦值語句不會有輸出結果。
練習 1
輸入以下語句,觀察Python直譯器的行為。 5 x = 5 x + 1 然後再把程式碼放在腳本里並執行該指令碼,看看會輸出了什麼結果。之後把每個表示式改成print語句再執行檢視結果。
2.7 運算順序
當表達始終出現多個運算子的時候,計算順序取決於優先等級。在算術運算中Python是遵循數學慣例的。英文縮寫PEMDAS可一幫助你記住預算規則: P - 括號具有最高優先順序,可以強制直譯器按所需順序計算,由於括號內的表示式優先計算,因此 2*(3-1) 等於4,(1+1)**(5-2)等於8(**表示冪運算)。你也可以運用括號讓表示式更容易閱讀,例如 (minute*100)/60 和 minute*100/60 運算結果是一樣的。 E - 冪運算的優先等級次之,所以2**1+1的結果是3,而不是4;3*1**3的結果是3,而不是27. MDAS - 乘法和除法具有相同的優先等級,其優先順序高於加法和減法,加法和減法則具有相同的優先順序。2*3-1等於5,而不是4;6+4/2等於8,而不是5。
優先順序相同的運算子按從左到右的順序計算(指數運算除外),在表示式 degrees / 2 * pi 中,先算除法然後結果再乘以pi。如果改成除以2 π,你可以用括號這樣寫 degrees/(2*pi)或者寫成degrees/2/pi。 我其實也不願意花太多時間去記運算子的優先順序的,如果我無法解釋表示式優先順序,我會使用括號讓表示式看起來簡單一些。
2.8 字串操作
通常,你不能對字串進行數學運算,即使字串看起來像數字,如下所示程式碼是非法的: '2'-'1' 'eggs'/'easy' 'third'*'a charm' “+” 運算子在字串操作中是可行的,但是可能不是你所期望的那樣:它執行連線操作,也就是把兩個字串首尾相連。 例如: first = 'throat' second = 'warbler' print first + second 輸出結果就是 throatwarbler “*” 運算子在字串操作中也是可行的,它執行重複操作,例如: 'Spam'*3 運算結果是 'SpamSpamSpam',也就是其中一個運算元是字串,而另外一個必須是一個整數。 對字串進行 + 和 * 操作的用法對比是有意義的,就像4*3等同於4+4+4,而'Spam'*3等同於'Spam'+'Spam'+'Spam'一樣。另一方面,字串串聯和重複操作跟整數的相加和相乘還是有顯著區別的,你能區分這裡面的不同屬性嗎?
2.9 註釋
隨著程式越來越大,越來越複雜,其閱讀難度也是越來越大。正式語言是龐雜晦澀的,通常很難檢視其中一段程式碼就弄明白它在做什麼和這麼做的原因。 出於這個原因,在程式中新增一些用自然語言說明程式的作用的文字,這是一個很好習慣。 這些說明文字就叫做註釋,一般以 # 開始。 # compute the percentage of the hour that has elapsed percentage = (minute * 100) / 60 在這個例子中,註釋內容是單獨一行顯示的。當然你也可以把註釋放在程式碼行的最後: percentage = (minute * 100) / 60 # percentage of an hour 每一行程式碼中從 # 開始的內容都會被忽略——這部分內容對程式無任何影響。 註釋在記錄程式程式碼的非明顯特性的時候是非常有用,只要能讓讀者能弄明白程式碼的作用這就是合理的,因此用註釋解釋原因是非常有用的。 但是下面這個註釋卻是無用的,多此一舉的。 v = 5 # 賦值5 給變數 v 而下面這個註釋卻包含著程式碼中沒有的有用的資訊 v = 5 # 5米/秒的速度 因此,好的變數名可以減少註釋的內容,但是太長的變數名又會顯得過猶不及,這個地方需要你自行權衡處理。
2.10 除錯
此時你最容易犯的語法錯誤是使用了非法的變數名,就像 class 或 yield,這些關鍵字是不能作為變數名的,又或者像odd~job和US$,這些變數名包含非法字元。 你如果在一個變數名中間加一個空格,Python就會認為這是兩個沒有操作符的運算元: >>> bad name = 5 SyntaxError: invalid syntax 對於語法錯誤,錯誤資訊通常沒有太大的幫助,最常見的語法錯誤就是 SyntaxError: invalid syntax 和 SyntaxError: invalid token。 執行時錯誤最常見的就是“先用後定義”,也就是在給某變數賦值之前就使用該變數,例如你把一個變數名拼寫錯了就會發生這個錯誤: >>> principal = 327.68 >>> interest = principle * rate NameError: name 'principle' is not defined 另外變數名是區分大小寫的,例如LaTeX和latex就是不一樣的。此時,最容易導致語法錯誤的情況就是使用變數的順序。例如:計算1/2 π,你可能會輸入如下程式碼: >>> 1.0 / 2.0 * pi 但是,按優先等級,除法是先進行計算,因此你將會得到的結果是π/2,而不是1/2π。此時Python並不知道你到底想要什麼結果,因此在這個例子中你得不到任何報錯資訊,因而你得到了一個錯誤的結果。
2.11 術語表
值: 資料基本單位,如數字或字串,程式操作等 型別: 值的分類。到目前為止有整數,浮點數和字元型。 整數: 表示整數的型別 浮點型: 用小數表示的數字型別 字元型: 表示字元序列的型別 變數: 值引用的名稱 語句: 表示命令或操作的程式碼。目前為止,語句包含賦值和列印語句。 賦值: 為變數賦值的語句 狀態圖: 用來表示變數及其值引用的圖形 關鍵字: 編譯器用來解析程式的保留字。例如if,def和while等關鍵字是不能用來作為變數名的。 運算子: 用來表示簡單計算,如加減乘除或字串級聯的特殊字元 運算元: 運算子所操作的值 向下取整: 兩數相除忽略小數部分 表示式: 由變數、運算子、值等表示求得數值的組合 求值: 通過操作來簡化表示式並獲得一個值 優先法則: 用於計算涉及多個運算子和運算元的表示式的順序的規則集 連線: 把兩個運算元首尾相連 註釋: 程式中的為了讓其他程式設計師(或任何閱讀原始碼的人)提供的對程式的執行沒有任何影響資訊。
2.12 練習
練習 2 假設我們執行以下賦值語句: width = 17 height = 12.0 delimiter = '.' 為下面每一個表示式寫下運算結果和結果型別(表示式的值) width/2 width/2.0 height/3 1 + 2 * 5 delimiter * 5 用Python直譯器檢查你的答案
練習 3 練習使用Python作為一個計算器: 1. 計算半徑為 r 的球體體積為:4/3 π r3,半徑為5的球體積是多少?提示:392.7 是錯的。
print(4/3*3.14159*5**3) 523.5983333333332
2. 假設一本書的價格是 $24.95,但是書店有40%的優惠,運費每次按第一本書 3$ 計算,超出的其它書按每本 0.75$ 計算。如果購買60本書則需要多少錢?
print('%.2f' % (24.95*(1-0.4)*60+3+0.75*59)) 945.45
3. 如果我在 6:52 從家裡出發,先慢速跑 1 英里(8分15秒),然後再快跑 3 英里(7分12秒),然後再慢跑1英里,請問我幾點能回到家吃早飯?
這一題我的解題思路是:先算出跑步一共花了多少分鐘,然後跟出發時間減一下,可以算出大概 7:30 能回到家 print((((8*60+15)*2+(7*60+12)*3)/60)) 38.1