1.1 引言
譯者:飛龍
計算機科學是一個極其寬泛的學科。全球的分佈式系統、人工智能、機器人、圖形、安全、科學計算,計算機體系結構和許多新興的二級領域,每年都會由於新技術和新發現而擴展。計算機科學的快速發展廣泛影響了人類生活。商業、通信、科學、藝術、休閒和政治都被計算機領域徹底改造。
計算機科學的巨大生產力可能只是因為它構建在一系列優雅且強大的基礎概念上。所有計算都以表達信息、指定處理它所需的邏輯、以及設計管理邏輯複雜性的抽象作為開始。對這些基礎的掌握需要我們精確理解計算機如何解釋程序以及執行計算過程。
這些基礎概念在伯克利長期教授,使用由Harold Abelson、Gerald Jay Sussman和Julie Sussman創作的經典教科書《計算機科學的構造與解釋》(SICP)。這個講義大量借鑑了這本書,原作者慷慨地使它可用於改編和複用。
我們的智力之旅一旦出發就不能回頭了,我們也永遠都不應該對此有所期待。
我們將要學習計算過程的概念。計算過程是計算機中的抽象事物。在演化中,過程操縱著叫做數據的其它事物。過程的演化由叫做程序的一系列規則主導。人們創造程序來主導過程。實際上,我們使用我們的咒語來憑空創造出計算機的靈魂。
我們用於創造過程的程序就像巫師的魔法。它們由一些古怪且深奧的編程語言中的符號表達式所組成,這些語言指定了我們想讓過程執行的任務。
在一臺工作正確的計算機上,計算過程準確且嚴謹地執行程序。所以,就像巫師的學徒那樣,程序員新手必須學會理解和預測他們的魔法產生的結果。
--Abelson & Sussman, SICP (1993)
1.1.1 在Python中編程
語言並不是你學到的東西,而是你參與的東西。
為了定義計算過程,我們需要一種編程語言,最好是一種許多人和大量計算機都能懂的語言。這門課中,我們將會使用Python語言。
Python是一種廣泛使用的編程語言,並且在許多職業中都有它的愛好者:Web程序員、遊戲工程師、科學家、學者,甚至新編程語言的設計師。當你學習Python時,你就加入到了一個數百萬人的開發者社群。開發者社群是一個極其重要的組織:成員可以互相幫助來解決問題,分享他們的代碼和經驗,以及一起開發軟件和工具。投入的成員經常由於他們的貢獻而出名,並且收到廣泛的尊重。也許有一天你會被提名為Python開發者精英。
Python語言自身就是一個大型志願者社群的產物,並且為其貢獻者的多元化而自豪。這種語言在20世紀80年代末由Guido van Rossum設計並首次實現。他的Python3教程的第一章解釋了為什麼Python在當今眾多語言之中如此流行。
Python適用於作為教學語言,因為縱觀它的歷史,Python的開發者強調了Python代碼對人類的解釋性,並在Python之禪中美觀、簡約和可讀的原則下進一步加強。Python尤其適用於課堂,因為它寬泛的特性支持大量的不同編程風格,我們將要探索它們。在Python中編程沒有單一的解法,但是有一些習俗在開發者社群之間流傳,它們可以使現有程序的閱讀、理解,以及擴展變得容易。所以,Python的靈活性和易學性的組合可以讓學生們探索許多編程範式,之後將它們新學到的知識用於數千個正在開發的項目中。
這些講義通過使用抽象設計的技巧和嚴謹的計算模型,來快速介紹Python的特性。此外,這些講義提供了Python編程的實踐簡介,包含一些高級語言特性和展示示例。通過這門課,學習Python將會變成自然而然的事情。
然而,Python是一門生態豐富的語言,帶有大量特性和用法。我們講到基本的計算機科學概念時,會刻意慢慢地介紹他們。對於有經驗的學生,他們打算一口氣學完語言的所有細節,我們推薦他們閱讀Mark Pilgrim的書Dive Into Python 3,它在網上可以免費閱讀。這本書的主題跟這門課極其不同,但是這本書包含了許多關於使用Python的寶貴的實用信息。事先告知:不像這些講義,Dive Into Python 3需要一些編程經驗。
開始在Python中編程的最佳方法就是直接和解釋器交互。這一章會描述如何安裝Python3,使用解釋器開始交互式會話,以及開始編程。
1.1.2 安裝Python3
就像所有偉大的軟件一樣,Python具有許多版本。這門課會使用Python3最新的穩定版本(本書編寫時是3.2)。許多計算機都已經安裝了Python的舊版本,但是它們可能不滿足這門課。你應該可以在這門課上使用任何能安裝Python3的計算機。不要擔心,Python是免費的。
Dive Into Python 3擁有一個為所有主流平臺準備的詳細的安裝指南。這個指南多次提到了Python3.1,但是你最好安裝3.2(雖然它們的差異在這門課中非常微小)。EECS學院的所有教學機都已經安裝了Python3.2。
1.1.3 交互式會話
在Python交互式會話中,你可以在提示符>>>之後鍵入一些Python代碼。Python解釋器讀取並求出你輸入的東西,並執行你的各種命令。
有幾種開始交互式會話的途徑,並且具有不同的特性。把它們嘗試一遍來找出你最喜歡的方式。它們全部都在背後使用了相同的解釋器(CPython)。
- 最簡單且最普遍的方式就是運行Python3應用。在終端提示符後(Mac/Unix/Linux)鍵入
python3,或者在Windows上打開Python3應用。(譯者注:Windows上設置完Python的環境變量之後,就可以在cmd或PowerShell中執行相同操作了。) - 有一個更加用戶友好的應用叫做Idle3(
idle3),可用於學習這門語言。Idle會高亮你的代碼(叫做語法高亮),彈出使用提示,並且標記一些錯誤的來源。Idle總是由Python自帶,所以你已經安裝它了。 - Emacs編輯器可以在它的某個緩衝區中運行交互式會話。雖然它學習起來有些挑戰,Emacs是個強大且多功能的編輯器,適用於任何語言。請閱讀61A的Emacs教程來開始。許多程序員投入大量時間來學習Emacs,之後他們就不再切換編輯器了。
在所有情況中,如果你看見了Python提示符>>>,你就成功開啟了交互式會話。這些講義使用提示符來展示示例,同時帶有一些輸入。
>>> 2 + 2
4
控制:每個會話都保留了你的歷史輸入。為了訪問這些歷史,需要按下<Control>-P(上一個)和<Control>-N(下一個)。<Control>-D會退出會話,這會清除所有歷史。
1.1.4 第一個例子
想像會把不知名的事物用一種形式呈現出來,詩人的筆再使它們具有如實的形象,空虛的無物也會有了居處和名字。
--威廉·莎士比亞,《仲夏夜之夢》
為了介紹Python,我們會從一個使用多個語言特性的例子開始。下一節中,我們會從零開始,一步一步構建整個語言。你可以將這章視為即將到來的特性的預覽。
Python擁有常見編程功能的內建支持,例如文本操作、顯示圖形以及互聯網通信。導入語句
>>> from urllib.request import urlopen
為訪問互聯網上的數據加載功能。特別是,它提供了叫做urlopen的函數,可以訪問到統一資源定位器(URL)處的內容,它是互聯網上的某個位置。
**語句和表達式:**Python代碼包含語句和表達式。廣泛地說,計算機程序包含的語句
- 計算某個值
- 或執行某個操作
語句通常用於描述操作。當Python解釋器執行語句時,它執行相應操作。另一方面,表達式通常描述產生值的運算。當Python求解表達式時,就會計算出它的值。這一章介紹了幾種表達式和語句。
賦值語句
>>> shakespeare = urlopen('http://inst.eecs.berkeley.edu/~cs61a/fa11/shakespeare.txt')
將名稱shakespeare和後面的表達式的值關聯起來。這個表達式在URL上調用urlopen函數,URL包含了莎士比亞的37個劇本的完整文本,在單個文本文件中。
**函數:**函數封裝了操作數據的邏輯。Web地址是一塊數據,莎士比亞的劇本文本是另一塊數據。前者產生後者的過程可能有些複雜,但是我們可以只通過一個表達式來調用它們,因為複雜性都塞進函數里了。函數是這一章的主要話題。
另一個賦值語句
>>> words = set(shakespeare.read().decode().split())
將名稱words關聯到出現在莎士比亞劇本中的所有去重詞彙的集合,總計33,721個。這個命令鏈調用了read、decode和split,每個都操作銜接的計算實體:從URL讀取的數據、解碼為文本的數據、以及分割為單詞的文本。所有這些單詞都放在set中。
**對象:**集合是一種對象,它支持取交和測試成員的操作。對象整合了數據和操作數據的邏輯,並以一種隱藏其複雜性的方式。對象是第二章的主要話題。
表達式
>>> {w for w in words if len(w) >= 5 and w[::-1] in words}
{'madam', 'stink', 'leets', 'rever', 'drawer', 'stops', 'sessa',
'repaid', 'speed', 'redder', 'devil', 'minim', 'spots', 'asses',
'refer', 'lived', 'keels', 'diaper', 'sleek', 'steel', 'leper',
'level', 'deeps', 'repel', 'reward', 'knits'}
是一個複合表達式,求出正序或倒序出現的“莎士比亞詞彙”集合。神秘的記號w[::-1]遍歷單詞中的每個字符,然而-1表明倒序遍歷(::表示第一個和最後一個單詞都使用默認值)。當你在交互式會話中輸入表達式時,Python會在隨後打印出它的值,就像上面那樣。
**解釋器:**複合表達式的求解需要可預測的過程來精確執行解釋器的代碼。執行這個過程,並求解複合表達式和語句的程序就叫解釋器。解釋器的設計與實現是第三章的主要話題。
與其它計算機程序相比,編程語言的解釋器通常比較獨特。Python在意圖上並沒有按照莎士比亞或者回文來設計,但是它極大的靈活性讓我們用極少的代碼處理大量文本。
最後,我們會發現,所有這些核心概念都是緊密相關的:函數是對象,對象是函數,解釋器是二者的實例。然而,對這些概念,以及它們在代碼組織中的作用的清晰理解,是掌握編程藝術的關鍵。
1.1.5 實踐指南
Python正在等待你的命令。你應當探索這門語言,即使你可能不知道完整的詞彙和結構。但是,要為錯誤做好準備。雖然計算機極其迅速和靈活,它們也十分古板。在斯坦福的導論課中,計算機的本性描述為
計算機的基本等式是:
計算機 = 強大 + 笨拙
計算機非常強大,能夠迅速搜索大量數據。計算機每秒可以執行數十億次操作,其中每個操作都非常簡單。
計算機也非常笨拙和脆弱。它們所做的操作十分古板、簡單和機械化。計算機缺少任何類似真實洞察力的事情...它並不像電影中的HAL 9000。如果不出意外,你不應被計算機嚇到,就像它擁有某種大腦一樣。它在背後非常機械化。
程序是一個人使用他的真實洞察力來構建出的一些實用的東西,它由這些簡單的小操作所組成。
—Francisco Cai & Nick Parlante, 斯坦福 CS101
在你實驗Python解釋器的時候,你會馬上意識到計算機的古板:即使最小的拼寫和格式修改都會導致非預期的輸出和錯誤。
學習解釋錯誤和診斷非預期錯誤的原因叫做調試(debugging)。它的一些指導原則是:
- 逐步測試:每個寫好的程序都由小型的組件模塊組成,這些組件可以獨立測試。儘快測試你寫好的任何東西來及早捕獲錯誤,並且從你的組件中獲得自信。
- 隔離錯誤:複雜程序的輸出、表達式、或語句中的錯誤,通常可以歸於特定的組件模塊。當嘗試診斷問題時,在你能夠嘗試修正錯誤之前,一定要將它跟蹤到最小的代碼片段。
- 檢查假設:解釋器將你的指令執行為文字 -- 不多也不少。當一些代碼不匹配程序員所相信的(或所假設的)行為,它們的輸出就會是非預期的。瞭解你的假設,之後專注於驗證你的假設是否整理來調試。
- 詢問他人:你並不是一個人!如果你不理解某個錯誤信息,可以詢問朋友、導師或者搜索引擎。如果你隔離了一個錯誤,但是不知道如何改正,可以讓其它人來看一看。在小組問題解決中,會分享一大堆有價值的編程知識。
逐步測試、模塊化設計、明確假設和團隊作業是貫穿這門課的主題。但願它們也能夠一直伴隨你的計算機科學生涯。