我要翻譯《Think Python》-003 第一章 程式設計之道
PDF原始檔地址 : http://www.greenteapress.com/thinkpython/thinkpython.pdf
[自述:翻譯第一章花了我大概一週的時間,雖然不是7*8小時的那種翻譯強度,只是工作之餘挑戰一下自己,讓我體會到翻譯就跟本章講的除錯一樣,它會讓你抓狂,鬱悶,沮喪。但是最終把這一章翻譯完成了,雖然自我感覺翻譯得不是很好,但還是蠻有收穫感的,有點挑戰自我的意思。目前離翻譯完成還有18章!!!]
第一章
程式設計之道
本書的目的在於教你如何像一個電腦科學家思考。這種思維方式結合了像數學,工程學和自然科學的一些有效的特性,就像數學家或者電腦科學家一樣用正式語言去表達想法(尤其是演算法)。讓你能夠像工程師那樣設計並安裝元件到系統裡,並且在眾多方案中評估選擇。或者像科學家那樣觀察複雜的系統行為,建立假設並驗證其真偽。 對於電腦科學家來說最重要一項技能就是解決問題。解決問題意味著提出問題,創造性的思考解決方案,並且清楚準確的表達出解決方案。事實證明,學習程式設計的過程就是鍛鍊解決問題能力的絕佳機會,所謂熟能生巧。這就是本章的標題為“程式設計之道”的原因。 一方面,學會程式設計是一項有用的技能。另一方面,運用程式設計可以達成目標。隨著我們繼續深入的學習,你會發現這個目標會越來越明確。
- 1.1 Python程式語言
Python是高階語言的一種,或許你還聽說過其它的一些高階語言,例如 C, C++, Perl 和 Java 等。當然也有一些低階語言,通常是指所謂的“機器語言”或者“組合語言”。簡單來說,計算機只能執行低階語言寫的程式。因此高階語言寫的程式執行之前需要處理,這額外的處理是需要時間的,這是高階語言的一個小瑕疵,但是瑕不掩瑜。首先,使用高階語言程式設計相對容易一些,你只要花很少的時間就能寫出更短,可讀性更強的程式碼,也很容易修正;其次,高階語言的可移植性很強,也就是說可以跨平臺執行(在某些平臺只需做很小的修改,甚至不需要修改),這是低階語言所不具備的特性(如需跨平臺執行必須重寫)。
由於高階語言的這些優勢,幾乎所有的程式都是用高階語言編寫,只有很少特定的程式還在使用低階語言。
有兩種程式可以把高階語言轉換為低階語言:直譯器和編譯器。直譯器讀取高階語言並且按程式邏輯執行,並且一次只能執行一個程式,逐行讀取程式並處理運算。直譯器結構如圖1.1所示。
圖1.1
編譯器則在程式執行之前讀取並轉換。高階程式稱之為原始碼,轉換器稱之為目的碼或可執行程式。程式只需要編譯一次,後面可以重複執行無需其他處理。編譯器結構如圖1.2所示。
圖1.2: 編譯器把原始碼轉換成目的碼, 並由硬體執行器執行.
Python程式是由直譯器來執行的,因此它是一種解釋型語言。它支援兩種模式:互動式模式和指令碼模式。互動式模式下,你輸入Python程式碼,直譯器則輸出結果:
>>> 1 + 1
2
“>>>” 是表示Python直譯器就緒的提示符,如果你輸入 1+1,直譯器則會輸出結果2.
或者,你可以把程式碼儲存在檔案裡,再使用直譯器來執行檔案,這就是指令碼模式。按照慣例,Python指令碼的字尾為.py。
執行指令碼必須提供完整的檔名給直譯器。例如指令碼檔名為 dinsdale.py 在UNIX命令視窗你需要輸入 python dinsdale.py 即可。在其它開發環境執行指令碼會有所不同,你可以從
互動模式適用於測試較少程式碼的情況,程式碼較多的情況建議採用指令碼模式,這樣方便你隨時修改和執行。
- 1.2 什麼是程式?
程式是為實現特定目標或解決特定問題而編寫的命令和指令。可能是解決數學問題,例如求方程式或求多項式的根,當然也可能是符號計算,例如搜尋或替換文件裡的文字或者編譯程式。 不同程式語言會有一些差異,但是所有語言都有相似之處:
- 輸入:
- 從鍵盤輸入,從檔案讀取,或者從其它裝置輸入
- 輸出:
- 顯示結果在螢幕上,儲存在檔案,或者輸出到其它裝置
- 數學:
- 提供基礎數學運算,例如加法和乘法
- 條件判斷:
- 驗證條件並執行相應的程式碼
- 迴圈:
- 提供一些迴圈操作,通常用來處理一些重複變化
信不信由你,這些就是程式語言的全部!不管你用過的程式有多麼複雜,它都基本都是由這些指令所組成。因此,你可以把程式設計理解為:把一個很大很複雜的任務拆分成很多小的子任務,直至簡單到可以用這些基本的指令來執行為止。此時概念可能會有點模糊,不過待後面我們探討到演算法的時候,我們還會回到這個話題上來的。
-
1.3 什麼是除錯?
程式設計是容易出錯的。程式錯誤稱之為Bug,而跟蹤除錯的過程稱之為除錯。 3種類型的錯誤可以在程式裡丟擲:語法錯誤,執行時錯誤和語意錯誤。除錯過程中區分這些錯誤型別可以讓你很快的消除錯誤。
-
1.3.1 語法錯誤
如果沒有語法錯誤,Python就可以執行指令碼。否則,直譯器就會丟擲錯誤資訊。語法是指程式結構和語法結構的規則。例如,括號必須是成對出現,如(1+2)是合法的,而缺一個括號,如 8) 則是是語法錯誤。 日常閱讀的時候,讀者往往可以忍受很多語法錯誤,因此我們可以無障礙閱讀E.E.卡明斯的詩歌。而Python則不同,只要程式中存在任何語法錯誤,它都會丟擲錯誤資訊並終止執行。因此在學習程式設計的初期,你可能會花費較多的時間去跟蹤語法錯誤,但隨著經驗的增長,發現和解決語法錯誤的能力會隨之增強。
-
1.3.2 執行時錯誤
第二種型別是執行時錯誤,顧名思義,這種錯誤是發生在程式執行的過程中的,也可以稱為異常。通常表示執行過程中的突發情況。本書的前幾章的範例中很少有這種錯誤。
-
1.3.3 語義錯誤
第三種就是語義錯誤。如果程式中有語義錯誤,雖然程式成功執行起來,並且不會產生任何錯誤資訊。但事實上程式並沒有按你所想的那樣去執行指令。 也就是說,程式並非按你的本意去執行的,你寫的程式在語義上是不對的。判斷語義錯誤相對比較麻煩,此時你只能通過檢視程式的輸出結果來搞清楚程式是如何執行指令的。
- 1.3.4 實驗除錯
對程式設計師而言,除錯能力是最重要的能力之一。雖然除錯的過程會讓你抓狂,但是你不得不承認除錯的過程很有挑戰性,這恰恰也是程式設計最大的樂趣。
在某種程度上,除錯過程就像偵探破案一樣。各種線索擺在眼前,然後你再推斷出導致結果的事件和過程。 除錯也像一門實驗科學,一旦你發現程式有問題,你會不斷的嘗試修改和測試。如果假設是正確的,那測試結果也一定是在預測範圍之內,反之亦然。正如夏洛特.福爾摩斯所說:“當你排除了所有的不可能,剩下的不管有多麼不可能,那一定就是真相。”(柯南道爾,《四人的標誌》) 對有些人來說,程式設計就是除錯。也就是說,程式設計就是一個逐步除錯的過程,直至程式完成你讓它做的事情。在我看來,你可以從頭開始做一個程式,逐步修改,除錯,直至做完一個完整的程式。 例如,Linux是一個開源作業系統,它的核心程式碼有上千行,不可思議的是,Linux是由Linus Torvalds編寫的一個探索英特爾80386晶片的一個簡單程式。據拉里.格林菲爾德所說,“Linus 早期做的這個專案,最初只是為了切換列印內容,並最終演化成現在的Linux系統。”(Linux使用者指南 測試版1) 在後面的章節裡面,我將會對除錯和程式設計實戰提出更多的建議。
- 1.4 正式語言和自然語言
自然語言:人們日常交流的語言,如英語,西班牙語,法語等等。這完全是自然流露,無需刻意修飾的語言。 正式語言:人們為特定程式設計的語言。例如,數學家在計算中表示數字與符號之間關係的語言就是正式語言;化學家用分子式表示化學結構也是正式語言。因此最重要的是:
-
- 程式語言是設計出來處理運算的正式語言。
正式語言有嚴格的語法要求。例如:3+3=6是正確的算式語句,而3+=3$6則是錯誤的。 語法規則有兩種風格,涉及到符號和結構。符號是語言的基本元素,如單詞,數字,化學元素等。3+=3$6之所以是錯誤的是因為$在數學計算中不是一個合法的符號(至少我是這麼認為的)。
第二種語法規則也與語句的結構有關,也就是說,符號是按序排列的,3+=3這個語句不對是因為即使+和=是合法的符號,但是卻不能把兩個符號同時放在一起使用(此處存疑,因為C語言中是支援x+=1這種寫法的)。
- 練習1
寫一條語法結構良好但是包含非法符號的句子,然後在寫下一條結構非法但是沒有非法符號的句子。 當你用正式語言閱讀的時候,你必須弄清楚句子的結構(儘管使用自然語言的時候是無意而為的),這個過程叫做解析。 舉個例子,當你聽到“The penny dropped”,你會想到“The penny”是主語,“dropped”是謂語,當你解析完整個句子,你才會明白這句話的意思或語義。假設你知道“penny”和“drop”是什麼意思,那麼這句話的意思你就基本清楚了。(字面意思是“錢掉了”,penny有“便士”的意思,習語表示“恍然大悟”的意思) 儘管正式語言和自然語言有很多共同點,例如符號,結構,語義和語法等,但是它們依然有區別: 歧義: 自然語言是具有模糊特性的,人類在使用自然語言的時候是會參考上下文的語境以及其他相關資訊的。而正式語言則不允許有任何歧義,它不管上下文的內容,每一句話只表達一種含義。 冗餘: 為了減少歧義並且避免誤解,自然語言包含了很多冗餘資訊,因此,自然語言有點囉嗦,而正式語言則更加簡潔。 文字: 自然語言裡面包含了很多習語和比喻。正如我前面說的“The penny dropped”,並不是說錢掉了(習語是說某人迷惑之後突然意識到了,有恍然大悟的意思),正式語言則按字面含義來理解。人類使用自然語言肯定無法適應正式語言的這種特性。從某些方面來說,自然語言和正式語言之間的差異就想詩歌和散文一樣,但不僅僅如此: 詩歌: 詩歌不僅意境深遠而且讀起來押韻唯美,主要是為了表達作者要抒發的情感,不僅晦澀難解,甚至字裡行間刻意為之! 散文: 散文則側重表達字面含義,字裡行間能提供更多內容,比詩歌更容易分析,但是也有詞不達意的情況。 程式: 計算機程式是沒有任何歧義的,是可以通過符號和結構的分析完全理解的。
這裡有一些閱讀程式的建議(包含其它的正式語言):首先,閱讀正式語言比閱讀自然語言需要更多的時間。另外,結構也很重要,並不是說從頭到尾閱讀一字不落的閱讀就能有助於理解。相反,在腦子裡直接解析程式結構和內容更有幫助。最後,細節決定一切,因為在自然語言中小的拼寫錯誤,發音錯誤是可以忽略的,但是正式語言則不然。
- 1.5 第一個程式
按照慣例,第一個程式通常稱之為“Hello, World!”,就是在螢幕上輸出文字“Hello, World!”,Python裡面只要這一句就可以:
print 'Hello, World!'
這是print用法,不是實際意義上的把內容列印在紙張上面,而是把內容列印在顯示器上,此時你可以在電腦螢幕上看到:
Hello, World!
程式中的引號是不顯示在列印內容裡面的,在Python3版本里,語法略有不同:
print('Hello, World!')
“()”在這裡說明print是一個函式,在後面第3章會介紹到函式的內容。在本書都將採用print語句,而不是print函式,如果你用的是Python3版本,請自行轉換,除此之外再無分歧。
- 1.6 除錯
如果你在學習本書內容的時候恰好在電腦旁邊,那將是非常好的,你可以選擇互動模式,即時執行程式碼,如果你採用指令碼模式那也是非常好的。 嘗試著犯錯有助於你瞭解語言的新特性,例如:把“Hello, World!”程式裡的引號去掉一個,或者兩個引號都去掉,又或者把print拼寫錯了將會導致什麼結果?這種型別的實驗不僅可以幫助你記住所學的內容,而且可以幫助你除錯,因為在這個過程中你將瞭解錯誤訊息的含義。在這個階段故意犯錯誤比無意中犯錯要好。 程式設計的過程中,尤其是在除錯的時候往往會讓你情緒激動,甚至與大BUG糾纏的時候你會感到憤怒,沮喪並且難堪。 事實證明,人對電腦的反應跟人對人的反應是一樣的。當電腦執行良好的時候,我們會把他們當成隊友,當電腦表現粗魯或者固執的時候,我們對他們的態度也是一樣。 預先了解電腦的這些特性或許對你有幫助,一是把電腦當成一個具有精確計算能力的員工,另外電腦有特定的缺陷,比如缺乏同理心沒有大局觀。你的工作就是做一個優秀的管理者,發揮電腦的優勢,弱化電腦的缺陷,不要因為情緒而影響到工作效率。雖說除錯工作會讓人沮喪,但它的確是很有價值的一項技能,即使是對程式設計以外的事情也是很有價值的。在本書的每一章結尾都會有調式的部分,期望這部分內容能夠幫助到你。
- 1.7 術語表
問題解決 表述問題,找到解決方案並表述解決方案的過程 高階語言 像Python這樣為了便於人類讀寫而設計的語言 低階語言 為計算機執行而設計的語言:機器語言,組合語言 可移植性 程式可以在不同平臺執行的屬性 解釋 逐行翻譯並執行高階語言編寫的程式碼 編譯 一次性把高階語言寫的程式翻譯成二進位制指令序列,形成目的碼 原始碼 用高階語言編寫的,未經編譯的字元流
目的碼 原始碼經過編譯器編譯之後輸出物件 可執行程式 目的碼的另一個表述:可執行檔案 提示符 直譯器顯示的字元,表示可以接收使用者的輸入 指令碼 存錯在檔案中的程式(通常需要直譯器進行翻譯) 互動模式 在Python直譯器中輸入程式碼並執行 指令碼模式 用Python直譯器讀取檔案中的程式碼並執行 程式 制定計算的指令集 演算法 解決同類型問題的一般過程 Bug 程式中的錯誤 除錯 發現並解釋發現的3中錯誤型別 語法 程式結構 語法錯誤 程式中無法完成語法解析的錯誤 異常 程式執行中檢測到的錯誤 語義 程式的含義 語義錯誤 程式中的一種錯誤,它讓程式不按程式設計師的意圖執行指令 自然語言 人類交流所使用的語言 正式語言 人類設計用於特殊目的,如表示數學思想或計算程式。所有程式語言都是正式語言。 符號 程式語法結構的基本要素之一,類似於自然語言裡的單詞。 解析 檢查程式並分析其語法結構。 列印語句 用Python直譯器在螢幕上顯示值
- 1.8 練習
練習2 訪問Python網站http://python.org 。這個頁面包含了Python的資訊以及和Python相關資訊的頁面,你能搜尋到Python的文件。 例如,你在搜尋框輸入print,你看到第一個連結就是print語句的文件。搜尋結果並非全都對你有幫助,但是聊勝於無。
練習3 開啟Python直譯器,輸入help()即可開啟線上幫助程式,或者直接輸入help('print')可以獲取到跟print 語句相關的資訊。如果不行的話,你需要檢查一下是否安裝了Python或者檢查一下環境變數,具體跟你的作業系統和Python版本有關。
練習4 開啟Python直譯器把它當成一個計算器。Python的數學計算語法幾乎跟標準數學運算是一樣的。例如+,-和/分別表示加,減和除,當然,正如你所料想的那樣,乘法符號是 * 。如果參加一個10公里長跑花了43分鐘30秒,那麼你的時速是多少英里?(提示:1英里大約1.61公里)
print(10/((43*60+30)/60/60)/1.61)
計算結果:
8.567144998929107