生產(chǎn)力水平的發(fā)展是人類歷史的主旋律。決定生產(chǎn)力水平的重要因素之一是生產(chǎn)工具。從這個(gè)角度講,人類歷史就是從石塊到計(jì)算機(jī)的歷史:從石器時(shí)代到信息時(shí)代。計(jì)算機(jī)是信息時(shí)代的主要生產(chǎn)工具,為了掌握這種工具,就要學(xué)習(xí)程序設(shè)計(jì)語(yǔ)言。
程序設(shè)計(jì)語(yǔ)言很多,相關(guān)的書(shū)籍更多。初學(xué)者常困惑于如何選擇入門語(yǔ)言①,一旦決定后又困惑于選擇什么教材。令人沮喪的是,選擇的機(jī)會(huì)成本并不低:一般初學(xué)者完整地學(xué)習(xí)某門編程語(yǔ)言需要一個(gè)月甚至更多時(shí)間。大專院校課程改革的機(jī)會(huì)成本則更高。有人說(shuō)選擇什么語(yǔ)言入門不重要,成為高手后自然兼通各種語(yǔ)言。這種說(shuō)法忽視了大多數(shù)學(xué)習(xí)者并不會(huì)成為高手的事實(shí),而且選擇性遺忘了他們自己作為初學(xué)者時(shí)所走的彎路?偠灾,學(xué)習(xí)者和教師在選擇適合入門的編程語(yǔ)言和書(shū)籍時(shí)應(yīng)當(dāng)謹(jǐn)慎行事。因此筆者有必要在前言中將寫(xiě)作意圖和內(nèi)容取舍進(jìn)行說(shuō)明,以作為讀者選擇的依據(jù)。
寫(xiě)作背景和目的
筆者在2018年秋接到邀約并著手寫(xiě)作,全稿終于2019年春。此時(shí)Python已經(jīng)躋身主流語(yǔ)言之列。之所以稱其為主流語(yǔ)言,在筆者看來(lái)有以下幾點(diǎn)證據(jù):
? 在各類有影響力的語(yǔ)言排行榜上,使用Python的比例開(kāi)始占據(jù)較大份額,排名也很靠前②;
? 在許多領(lǐng)域,Python成為主要的編程語(yǔ)言,甚至是首選語(yǔ)言,例如在數(shù)據(jù)分析、人工智能和服務(wù)器開(kāi)發(fā)等領(lǐng)域;
? 教育部將Python納入了國(guó)家計(jì)算機(jī)等級(jí)考試的科目③。
而在此之前其已經(jīng)得到了廣泛應(yīng)用:
? Python逐漸成為許多國(guó)際一流高校程序設(shè)計(jì)課程的教學(xué)語(yǔ)言;
? 許多基礎(chǔ)軟件框架采用Python作為設(shè)計(jì)語(yǔ)言或提供Python的編程接口;
? Python在開(kāi)源軟件界和工業(yè)界已廣受歡迎。
上述事實(shí)是筆者決定基于Python編寫(xiě)本書(shū)的原因④。其他的原因則是在教學(xué)中無(wú)合適教材可用。數(shù)年前筆者領(lǐng)導(dǎo)團(tuán)隊(duì)設(shè)計(jì)Python課程體系,那時(shí)曾經(jīng)遍訪各種Python書(shū)籍和教程。當(dāng)時(shí)的Python書(shū)籍或者是簡(jiǎn)單的手把手入門,或者是大部頭的知識(shí)大全,或者是應(yīng)用于某具體領(lǐng)域的手冊(cè)指南。
隨著近年來(lái)Python教學(xué)實(shí)踐的展開(kāi),市面上開(kāi)始出現(xiàn)各種教科書(shū)體裁的Python書(shū)籍(如羅伯特塞奇威克等所著的《程序設(shè)計(jì)導(dǎo)論:Python語(yǔ)言實(shí)踐》)。那為何還要再寫(xiě)一本同樣主題的教科書(shū)呢?因?yàn)榻虒W(xué)對(duì)象不同,教學(xué)目標(biāo)有所差別,教學(xué)過(guò)程各有側(cè)重。所以教科書(shū)的首要價(jià)值在于不同。這種不同在本書(shū)來(lái)說(shuō)至少有兩個(gè)層面,一是Python與其他語(yǔ)言的不同,二是本書(shū)與其他Python書(shū)籍的不同。
學(xué)習(xí)或講授新知識(shí)時(shí),首先應(yīng)注意到的往往是其與原有認(rèn)知的相同之處,但唯有深入理解并能運(yùn)用其不同后,才算窺得門徑。例如Python也有循環(huán)、分支和函數(shù)等各種語(yǔ)言俱有之概念,但學(xué)習(xí)者如只見(jiàn)共性,并由此得出Python很簡(jiǎn)單的結(jié)論,便失去了學(xué)習(xí)新語(yǔ)言的意義。教師在教學(xué)生時(shí)也不能僅僅按照講授舊有語(yǔ)言的經(jīng)驗(yàn),把講義中的例子依次用Python重寫(xiě)一遍了事。①
書(shū)的不同則在于體裁形式、內(nèi)容取舍編排和作者觀點(diǎn)的不同。既然是教科書(shū),總不大好寫(xiě)成對(duì)話體,也不適宜畫(huà)成漫畫(huà)②。所以教科書(shū)的不同主要體現(xiàn)在取舍、次序、示例和觀點(diǎn)等方面。然而寫(xiě)一本完全不一樣的書(shū)是很難的,尤其是在Python已經(jīng)相當(dāng)流行的當(dāng)下。③
不同總是相對(duì)的,各種相對(duì)性參照中,對(duì)讀者來(lái)說(shuō)最重要的參照便是讀者自身。初來(lái)者看處處皆是新奇,見(jiàn)多識(shí)廣后則覺(jué)得不過(guò)爾爾。所以下文僅對(duì)本書(shū)內(nèi)容的取舍和編排進(jìn)行說(shuō)明,至于其中有何不同則留待讀者自己體會(huì)。
取舍
在教科書(shū)中全面講授Python的細(xì)節(jié)是不現(xiàn)實(shí)的(這里說(shuō)的語(yǔ)法細(xì)節(jié)包括完整的語(yǔ)法模型、各種對(duì)象的API④,以及各種標(biāo)準(zhǔn)庫(kù)),原因有以下幾點(diǎn):
? 過(guò)多的細(xì)節(jié)會(huì)喧賓奪主,無(wú)法凸顯真正重要的核心內(nèi)容;
? 語(yǔ)言中的艱深部分不適合本書(shū)面向的教學(xué)階段,也不常用于多數(shù)程序員的日常工作;
? Python標(biāo)準(zhǔn)庫(kù)包羅萬(wàn)象,全面介紹是不現(xiàn)實(shí)的(無(wú)論從篇幅上還是讀者的知識(shí)背景基礎(chǔ)而言);
? Python在不斷發(fā)展,其細(xì)節(jié)仍然在不斷變化中。
筆者認(rèn)為,既然在整體上無(wú)法面面俱到,那么在局部也不應(yīng)有這種負(fù)擔(dān)。例如異常處理這一主題,如果完整地講授異常機(jī)制的每個(gè)細(xì)節(jié)(如各種內(nèi)建異常類型),則需要相當(dāng)多的篇幅①。但真實(shí)的情況是:絕大多數(shù)的工程師根本不懂如何處理程序的意外情況,不論是使用C語(yǔ)言這樣沒(méi)有異常處理機(jī)制的語(yǔ)言,還是使用Java或Python這樣有完整異常處理機(jī)制的語(yǔ)言。究其原因有以下幾點(diǎn):
? 一是初學(xué)者沒(méi)有能力接受太多的異常處理知識(shí),正常程序還寫(xiě)不明白,哪里有精力去整什么異常處理;
? 二是異常處理的核心在于全面、準(zhǔn)確地剖析程序的各種意外情況,不具備這個(gè)能力,學(xué)習(xí)再多的異常處理機(jī)制也是枉然;
? 三是在學(xué)習(xí)程序設(shè)計(jì)的初級(jí)階段,往往用算法進(jìn)行練習(xí)(比如走個(gè)迷宮、匹配個(gè)字符串),不和復(fù)雜的外部世界(如網(wǎng)絡(luò))打交道;
? 四是考慮到教學(xué)重點(diǎn)和敘述篇幅,也往往假定數(shù)據(jù)有效,這樣就不用考慮處理意外情況。這樣一來(lái),教學(xué)中費(fèi)大力氣講授的異常處理機(jī)制,也因?yàn)闀簳r(shí)無(wú)用而被拋諸腦后。
本書(shū)則不糾纏于異常處理的細(xì)節(jié)和內(nèi)建異常的類型,而是在講述完基本語(yǔ)法后詳細(xì)剖析一個(gè)程序?qū)嵗?.10.2節(jié)),展示如何分析和處理各種意外的輸入情況,篇幅上也僅限制為一節(jié)。讀者若能吃透這一部分內(nèi)容,則當(dāng)有編寫(xiě)健壯程序的意識(shí),自能夠在工作中舉一反三,也無(wú)須筆者再行贅述。反之,若對(duì)健壯性不夠重視,則多費(fèi)篇幅也沒(méi)有意義。
作為這種取舍思路的補(bǔ)充,本書(shū)有時(shí)會(huì)指出一些自學(xué)內(nèi)容,將其留作練習(xí),并引導(dǎo)讀者進(jìn)行思考或通過(guò)網(wǎng)絡(luò)查閱相關(guān)資料。作為編程入門教科書(shū),本書(shū)首要講述程序設(shè)計(jì)的一般性方法,例如:
? 數(shù)據(jù)類型、流程控制、輸入/輸出和函數(shù)等基本手段;
? 狀態(tài)機(jī)、遞歸、函數(shù)式編程等高級(jí)技巧;
? 數(shù)據(jù)結(jié)構(gòu)和算法;
? 面向?qū)ο蟮脑O(shè)計(jì)思想。
對(duì)Python自身語(yǔ)法的介紹,也在本書(shū)各部分占據(jù)了相當(dāng)篇幅。然而本書(shū)終歸不是語(yǔ)法手冊(cè),所以并不追求語(yǔ)法知識(shí)細(xì)節(jié)的完整性。書(shū)中大部分小節(jié)后會(huì)給出延伸的問(wèn)題和練習(xí),或是明確的編碼練習(xí),或是要求讀者進(jìn)行深入地學(xué)習(xí)和思考,統(tǒng)稱為思考和擴(kuò)展練習(xí)。本書(shū)在設(shè)計(jì)和挑選例題時(shí)力圖做到和傳統(tǒng)的程序設(shè)計(jì)入門書(shū)籍在角度和深度上有所差異,目的在于為學(xué)生和教師提供更加開(kāi)闊的思路。
計(jì)算機(jī)程序設(shè)計(jì)的理論基石(如語(yǔ)言基本模型、數(shù)據(jù)結(jié)構(gòu)和算法)是在半個(gè)世紀(jì)前奠定的。雖然Python誕生的年代稍晚,但也基于這些基石構(gòu)建而成。Python的主體部分是基于樸素平實(shí)的想法構(gòu)建而成,而非天才的靈光一現(xiàn)。本書(shū)的一個(gè)重要初衷就是將這些樸素呈現(xiàn)給讀者。筆者舍去了一些和該初衷無(wú)關(guān)的內(nèi)容,如傳統(tǒng)教學(xué)中往往著重介紹的字符串顯示控制標(biāo)記,在本書(shū)中只是一帶而過(guò)。而那些更為深層次的基本概念則得到了強(qiáng)化,例如狀態(tài)機(jī)模型、遞歸消除、面向?qū)ο髣?dòng)機(jī)及性能權(quán)衡等。
本書(shū)在示例中堅(jiān)持給出完整可執(zhí)行的代碼或交互界面步驟,然而本書(shū)絕非手把手的教程。書(shū)中有些內(nèi)容對(duì)于學(xué)習(xí)者來(lái)說(shuō)是具有相當(dāng)難度的,需要讀者反復(fù)閱讀思考并且動(dòng)手實(shí)踐才能夠理解或掌握。這種難度是具有現(xiàn)實(shí)意義的:較難內(nèi)容大多數(shù)來(lái)自于工程實(shí)踐、后續(xù)學(xué)習(xí),甚至是求職面試中的重點(diǎn)。讀者應(yīng)當(dāng)認(rèn)識(shí)到對(duì)這些問(wèn)題的思考能力和思考過(guò)程的重要性。
內(nèi)容編排
本書(shū)分為4章,取名為:
? 第1章 基礎(chǔ);
? 第2章 函數(shù);
? 第3章 數(shù)據(jù)結(jié)構(gòu);
? 第4章 面向?qū)ο蟆?/p>
上述各章內(nèi)容并非涇渭分明,原因主要在于Python的知識(shí)點(diǎn)存在許多循環(huán)依賴,如圖1所示。例如for循環(huán)用到了迭代器的概念,而講授迭代器需要足夠的面向?qū)ο笾R(shí),繞過(guò)分支控制先完整地講述面向?qū)ο笠膊滑F(xiàn)實(shí)。對(duì)于有經(jīng)驗(yàn)的讀者來(lái)說(shuō),這沒(méi)有任何問(wèn)題,但對(duì)初學(xué)者則會(huì)造成很大困擾。基于這些原因及教學(xué)實(shí)踐,本書(shū)在第1章中簡(jiǎn)要講授了函數(shù)定義而非拖至第2章,將定義類的基本方法提前至第2章而不是留待第4章。這兩節(jié)內(nèi)容的調(diào)整是本書(shū)的重要關(guān)節(jié)。
圖1 知識(shí)點(diǎn)的循環(huán)依賴
這4章內(nèi)容以第1章篇幅最長(zhǎng),第2、3章次之,第4章最短。程序的基本設(shè)計(jì)方法、異常處理和程序調(diào)試等內(nèi)容歸入了第1章。模塊和迭代器歸入了第2章。部分內(nèi)建類型,如字典的深入講解歸入了第3章。在第4章面向?qū)ο笤O(shè)計(jì)部分,考慮到相應(yīng)的學(xué)習(xí)階段課時(shí)、Python的混合風(fēng)格特性和簡(jiǎn)潔的面向?qū)ο笳Z(yǔ)法,筆者決定精簡(jiǎn)篇幅而非長(zhǎng)篇大論。另外,由于在Python中對(duì)象模型和面向?qū)ο笳{(diào)用風(fēng)格的無(wú)處不在,許多相關(guān)知識(shí)已經(jīng)散見(jiàn)于前3章,也沒(méi)必要再次重復(fù)講述。
習(xí)題
本書(shū)沒(méi)有單獨(dú)整理的習(xí)題集。首先是因?yàn)楣P者水平所限,并且時(shí)間也有限,無(wú)法設(shè)計(jì)大量的原創(chuàng)習(xí)題。另一個(gè)原因是筆者反對(duì)采用在語(yǔ)言學(xué)習(xí)階段使用刷題的方式提升編程能力①。讀者如能將本書(shū)示例及每小節(jié)末尾的思考和擴(kuò)展練習(xí)完成,在筆者看來(lái)就足夠了。如果讀者在完成這些內(nèi)容后仍覺(jué)不足,不要把精力浪費(fèi)在所謂的習(xí)題集或面試寶典上,而應(yīng)該去學(xué)習(xí)更為深入的主題(如操作系統(tǒng)、網(wǎng)絡(luò)、算法或編譯原理等),或投身于解決實(shí)際問(wèn)題。
參考文獻(xiàn)
本書(shū)中提到的若干算法、觀點(diǎn)、文檔和源碼的原始出處在書(shū)尾以參考文獻(xiàn)的形式給出。閱讀原始文獻(xiàn)是非常有必要的。通過(guò)對(duì)這些文獻(xiàn)的閱讀,即便是少量閱讀,學(xué)習(xí)者也能夠體會(huì)到創(chuàng)造者當(dāng)時(shí)的心境。這看似增加了額外的學(xué)習(xí)任務(wù),但實(shí)為捷徑。為了便于讀者檢索,筆者用[1][2]的編排格式給出了所對(duì)應(yīng)的參考文獻(xiàn)序號(hào)。
版本
筆者在Mac計(jì)算機(jī)上完成了絕大部分的寫(xiě)作工作。寫(xiě)作時(shí)的Python最新版本是3.7。當(dāng)然這絕不意味著讀者也需要搞一套這樣的軟硬件環(huán)境。使用Linux的讀者不用太過(guò)擔(dān)心兼容性問(wèn)題。使用Windows系統(tǒng)的讀者除去1.6.3節(jié)中管道行的相關(guān)命令外,應(yīng)當(dāng)可以順利運(yùn)行本書(shū)中的其他程序。筆者平時(shí)并不使用Windows系統(tǒng),所以本書(shū)示例在Windows平臺(tái)上可能會(huì)稍有更多的兼容性問(wèn)題。但跨平臺(tái)的兼容性帶來(lái)的麻煩遠(yuǎn)不及Python本身升級(jí)帶來(lái)的兼容性問(wèn)題。所以在學(xué)習(xí)時(shí)糾結(jié)于應(yīng)當(dāng)使用哪種操作系統(tǒng)平臺(tái)是意義不大的,因?yàn)镻ython未來(lái)的某次升級(jí)可能導(dǎo)致本書(shū)代碼無(wú)法運(yùn)行的情況更多。好在互聯(lián)網(wǎng)的便利使得筆者對(duì)本書(shū)出版后做勘誤和代碼更新很容易,筆者會(huì)將本書(shū)的勘誤信息和最新的升級(jí)信息反饋給出版社,讀者可在出版社的官網(wǎng)上找到本書(shū),獲取這些資料。
格式約定
為了便于讀者學(xué)習(xí),本書(shū)堅(jiān)持給出絕大多數(shù)示例的完整代碼及運(yùn)行效果。有的代碼示例直接運(yùn)行即可看到期望的結(jié)果,而有的代碼則需要進(jìn)行一些樣例輸入或者將其導(dǎo)入后調(diào)用。本書(shū)統(tǒng)一將這些運(yùn)行結(jié)果或運(yùn)行示例稱為程序運(yùn)行結(jié)果。
本書(shū)用以下格式表示代碼實(shí)例。這些實(shí)例大部分能夠直接運(yùn)行,少部分需要讀者自行補(bǔ)充完整。
本書(shū)用以下格式表示交互執(zhí)行的過(guò)程和結(jié)果。
其中, $ 表示操作系統(tǒng)的終端(shell)提示符,>>>表示Python的交互式執(zhí)行環(huán)境提示符。該格式還用來(lái)排版批量的文本,例如:
至于在說(shuō)明文字中用到的解釋性代碼,則直接用如下格式排版:
本書(shū)的代碼參考Python的推薦風(fēng)格PEP-8,但有時(shí)為了行文緊湊也會(huì)縮減空格及空行。
獲取配書(shū)資料
本書(shū)提供以下配書(shū)資料:
? 配套教學(xué)視頻;
? 實(shí)例源代碼文件;
? 教學(xué)PPT。
這些資料需要讀者自行下載。請(qǐng)登錄華章公司網(wǎng)站,在該網(wǎng)站上搜索到本書(shū),然后單擊資料下載按鈕,即可在本書(shū)頁(yè)面上找到下載鏈接。
讀者對(duì)象
本書(shū)的最佳讀者設(shè)定是有教師指導(dǎo)的程序設(shè)計(jì)初學(xué)者,筆者稱之為教科書(shū)設(shè)定。這意味著本書(shū)不會(huì)教讀者諸如安裝執(zhí)行環(huán)境和使用代碼編輯器這類準(zhǔn)備工作。這是教師的職責(zé)。如果讀者是自學(xué)者,那么你應(yīng)當(dāng)首先確保自己正確地安裝了Python運(yùn)行環(huán)境,并嘗試編輯一兩個(gè)Python小程序運(yùn)行一下。這在今天很容易,讀者只需要隨便找一個(gè)在線視頻,看上二三十分鐘即可。對(duì)于自學(xué)者來(lái)說(shuō),找到幾位Python的使用者去獲取一些初始建議,并且能夠在學(xué)習(xí)遇到困惑時(shí)求助也是非常重要的。很多人在學(xué)習(xí)過(guò)程中因?yàn)槟承┎唤?jīng)意的障礙而放棄。比如原本代碼寫(xiě)對(duì)了,但某個(gè)執(zhí)行路徑不對(duì),在反復(fù)檢查代碼后依然失敗而信心全無(wú)。
本書(shū)還特別適合一類讀者,即學(xué)過(guò)一些程序設(shè)計(jì)語(yǔ)言的粗淺知識(shí),馬馬虎虎地寫(xiě)過(guò)一些程序,處于某種目的又希望認(rèn)真、正式地學(xué)習(xí)程序設(shè)計(jì)的學(xué)生。他們有可能是打算大學(xué)畢業(yè)希望找一份IT工程師工作的學(xué)生,也可能是中學(xué)階段學(xué)過(guò)一些編程后希望在這條路上走得更遠(yuǎn)的學(xué)生。對(duì)這類讀者來(lái)說(shuō),本書(shū)將帶給他們更加深厚的基礎(chǔ)能力。
致謝
本書(shū)的寫(xiě)作得到了好友姜寒先生的大力協(xié)助。姜先生有豐富的實(shí)踐經(jīng)驗(yàn),又兼通各種主流程序設(shè)計(jì)語(yǔ)言。筆者在寫(xiě)作本書(shū)時(shí)多有疑難困阻,或關(guān)于Python本身,或關(guān)于其他廣泛主題;又有時(shí)在詳略取舍上難以決斷,或是對(duì)一些觀點(diǎn)信心不足。每每及此,與姜先生討論后總能破除心中所障。除此之外,姜先生還審閱了本書(shū)的部分章節(jié),從內(nèi)容到行文,均提出了寶貴意見(jiàn)。
張頔于北京