日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

简明python指南(预览版)

發布時間:2023/12/18 python 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 简明python指南(预览版) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文作者:NTFS

因為,全文比較長,沒有經過完整的校對,紕漏難免。

當前最新版本的 pdf 在此 -> 關注公眾號 “ 無知紅 ” 回復? “?簡明python指南 ” 即可獲取下載鏈接

以下內容是為了方便搜索引擎索引特別加上的,不是給人看的。因此不進行頻繁修補,只做積累更新(最后更新于2015年10月14日)。

PS:全文兩萬六千余字,目前32頁,因為字數限制,不能完整復制進來。加之簡書的功能實在很爛,于是圖片和腳注就不一一補充了


本來這個是某系列連載文章中的第二期的第十五篇,不過限于篇幅,我覺得還是獨立出來比較好。寫這個指南的目的,是幫助大多數想接觸python的人更方便更全面的認識這門編程語言并學會如何運用這套工具集。

與此同時我覺得現如今關于python的書大多都是多余的,它們花了很大的篇幅在講些沒用或者不相干的東西。很多書假定你對編程的理解還很模糊,假定你可能用著不同的操作系統,其實這對于大多數我的目標讀者來講,都是多余的。當然那也是出版社的無奈,我自然無所謂,我可以假定大家都用的windows,還都是xp以上,只要不影響行文就好。另外這個標題里的簡明一詞,是相對一本書的厚度而言的。

我最早知道python是09年,那時候還在用塞班的s60手機。后來是GAE,那時候版本還是2.5.x,不過因為已經高三了也就沒去折騰。最初開始用python大概是從2012年秋季休學的時候算起,現在轉眼都2.7.9了。眼看著python2的時代已然走到了盡頭,雖然大家都還會繼續用,只是過去的時光早已兇猛地從身邊流逝了。

最初打算寫關于python的教程是在2013年春。之前2011年剛高考完的時候想自己做個網站,于是2012年春的時候決定學python(主要受豆瓣的啟發)。然而拖拖拉拉,直到那年秋末休學才開始投入起來。到2013年的時候基本的東西都會的差不多了,正好社團里有不少新人感興趣,于是也打算教他們來一起玩,大概寫教程的想法最早是這時候有的。后來就是一個悲劇的故事,我復學之后沒能掌控好自己的節奏掛了許多課,社團這邊的活動也沒組織得好,外面幫公益機構做的東西也是一拖再拖直到爛尾。最后我選擇降級到13級,雖然去年秋季有寫些教程的草稿,但后來今年上半年因為個人問題不得不在家待半年,差不多都忘了。直到七月我回到學校,八月有人有重新跟我提起python的時候,這個中斷了N次的想法才得以重新喚醒,雖然最后那個網站我并沒有做出來。其實相比13/14年時候的想法,這些年來我對python的理解也有不少變化,尤其是在我接觸了erlang和APL以后。這也是我決定丟掉去年的草稿重新寫過的主要原因之一(另一方面是我忘記存哪了不太好找……)。

不過由于第一次寫這種稍微正式一點的教程,字數會有點多。也許精簡一下,或者說真正有用的部分估計不到6000字,然而這個環節要我自己察覺出來很不容易,所以如果能收到些反饋建議,而我也會對應做些改進,兩全之策,豈不美哉。

另外,我建議記性不太好或者動手能力較差的,去打印一份(或者一部分)紙質版放在床頭,雖然第一版是有點坑,不過我想說的其實是,有些時候紙質版的東西看上去更入眼。

目標讀者

其實并沒有很具體的目標,用這個二級標題只是在假裝很嚴肅的樣子。一開始定位在大一大二的小盆友(那是14年的時候,現在他們都大三大四了),不過就現在的情況發展下去,小學六年級以上也是可以的。

為什么學python?

這是很多書要跟你講的第一章,很遺憾,我不會告訴你為什么。因為老實說python并不是一門很適合用來教學的語言,不過呢,它就是能用來偷懶,所以大家都用它。本質上來說,學會python并不是簡單的學習它的語法和各種概念,而是學會讀懂別人的python代碼,學會自己寫python,以及熟悉整個python的工具鏈和生態環境以致如何做項目等等。就是這樣。而實際上學python是一個實踐和積累的過程,也就是說本文并不能幫你太多。

準備工作

你需要裝一個python解釋器。我不會跟你解釋具體解釋器是什么鬼以及和編譯器有什么差別,你所需要做的,就是理解這個過程并照著做一遍,碰到看不懂的地方,自己去搜一下或者直接問我也行->absente@live.cn。

同樣的,我也不會跟你講太多什么是python2和python3的區別。這里你只需要下載個anaconda python2的集成環境就好。

然后是編輯器。初學我覺得sublime text 3或者notepad2-mod都可以,當然如果要推薦的話,我覺得sublime和pycharm就夠了。vs2015其實也可以,不過有點太重型了,而且關鍵是我并不太熟悉…

還有就是備上兩份文檔,python2和python3的。Anaconda實際上會附上一份python2的chm文檔,然而要自己去目錄里找出來。這里個人覺得chm文檔還是夠用的,當然,如果你習慣多標簽閱讀,那么html的更適合你,如果是電子書的話,官網也有pdf。另外我推薦用那種專門的離線文檔工具,比如zealdocs(mac下的是dash)。

這里附上windows下可用的anaconda和sublime text 3以及pycharm,zeal和官方的chm/html/pdf文檔:

#百度網盤鏈接(合集):http://pan.baidu.com/s/1dD6nVn7

Python:https://www.python.org/

Anaconda:http://continuum.io/downloads

Sublime text 3:http://www.sublimetext.com/

Pycharm 4:https://www.jetbrains.com/pycharm/

Zeal / Dash:https://zealdocs.org/

裝anaconda的時候一路默認next,這樣python的執行路徑應該也就在PATH環境變量里了,當然如果你實在是閑anaconda太大,也可以自己下個官方的Python,然后選擇加到環境變量里。其實加到PATH里面并不是總是必須的,只是通常為了方便調試就成了潛規則。

語法概要

你可能覺得上來就講語法會不會有點消化不良?其實不會的。所謂編程語言的語法,就是按照一定的符號規則去表達你的邏輯和程序流程。

在這里我覺得有必要列舉一下其他語言的語法。首先是c語言(以下都是單行代碼):

void main(){}

上面是一段合法且并沒有什么卵用的c代碼。本來想舉個java的例子,不過好像不太確定怎么寫,就搜了一下hello world,然后改了改,但是不確定是否一定合法,于是就放棄了。換成js:function

main(){}或者匿名函數形式的main = function(){}

然后是python:

def main(): pass或main =lambda: None

我們在這里不是要對比出什么優劣,那是西方人喜歡干的事情,而且相對沒什么意義。這里我們需要做的是尋找其中的共性。比如你會發現它們都可以用圓括號來表示參數區域。

感覺真要講語法的話,到這里就差不多了,最多給你強調一下,縮進一定要用四個空格,區塊注釋要用雙引號。實際上python的語法并沒有多復雜。很多語法關鍵字剛入門的話根本用不到,而且也不是那么容易搞懂(比如with和yield)。于是你只需明白幾個基本概念就可以寫python代碼了。當然這里并不鼓勵你馬上去寫個hello world,因為那也沒什么實際意義,而且不太符合我國的教育習慣。這里我的思路是先講點概念,然后教你怎么讀懂python代碼,然后再去改或者去寫。當然,語法不可能就說這么點,那是開玩笑的。在講概念之前,正經地補充點語法常識還是有必要的。

首先,python用縮進替代了大括號來限定作用域(縮進這個設定有好有壞,不過算是python比較明顯的一個特征之一),當然,和傳統編程語言一樣,實際上限定作用域(或者說語法單元)的還是小括號。然后你可能會說為什么不強調沒有分號這個問題,其實,python是允許分號的,只是依照潛規則,大家都不用而已。而且,如果你喜歡的話,還可以開啟大括號縮進模式…不過出于人身安全考慮,不要這么做,這樣只會被當作異教徒。

先說邏輯相關的,有幾個關鍵字:and,or,not和is,==,!=,雖然這個用來替換&&, ||,!好像更直觀了,但是有時候也會搞暈人。另外,邏輯運算的返回值只有兩個,True和False,首字母大寫。至于None這個是獨立出來的一個值,對應C里面的null。容易搞混的地方自己動手試試最好做個筆記。is和==通常是不會等價的,所以如果一個值你能確定全等的時候,才盡量用is。用is的好處是有時候邏輯表達可以更連貫一點(有些時候計算效率也更高),比如A is B。但有時候也不一定符合表達習慣,比如A is not B。還有就是要明白,[] is []這種肯定是False的,因為不同的列表指向的內存空間肯定不同。

除了前面說到None,Python和C里面很多概念都是可以對應上的,這個往后用久了會有更多體會,但是要注意的是python也有自己提倡的一些潛規則,比如PEP8,然而這里面的很多規則實際上和C是不完全對應的,這也是我為什么個人并不提倡完全遵循pep8的原因之一。

說到這種潛規則,不得不提一下python的命名規則,變量和函數命名也是很重要的一個細節,python推薦用小寫字母加下劃線比如:blue_shit,如果是class的話會推薦你寫作HolyShit,至于class method很多人也推薦小寫加下劃線(eat_shit)不過個人覺得繼續用java那種小寫字母開頭的駝峰寫法(eatShit)也不是什么壞事(畢竟Google也是這么玩的不是么)。不過通常來講,個人自從用慣erlang之后就不再特別講究這個了。比如前面的blue_shit可以縮寫作S或BS/SB隨意,有時候變量本身的意義并不是那么重要,只要不影響邏輯就好。所謂的代碼可讀性,其實只在你需要讀懂代碼的前提下才有意義,而有時候我們不用搞懂代碼,只要會用就好了,這個概念比較類似道家的無用,不過外國人多半是搞不懂的。

流程控制方面,主要就是if和for,然后while用的很少(一般也就是結合yield或者來個mainloop),沒有switch,switch用if和elif的組合代替。然后,python的else比較奇葩,if,for,while都可以在屁股后面加個else。if...else比較好理解,for...in后面的else只在for循環沒有break的情況下最后執行(也就是補刀用,如果for沒有完整走完是不會有的),while后面的else同理。然后,break跟continue是想反的,和c一樣。不過python里面有個pass,這個語句沒有啥作用,一般用在def后面臨時寫個空函數,然后結果和def a():return None是一樣的。下寫if分支的時候,你可以用pass臨時占個位置。因為單獨寫個注釋在build的時候還是會報錯的,而補上pass就沒事了。另外如果習慣了pass之后,可以用來標注某些未實現的功能,方便查找。還有就是,如果你習慣c里面的三元表達式即Z=X?A:B這種,python也提供了一個類似的語法糖即Y=A if X else B。后者可能對于印歐語系的人更為直觀一點,然而對于天朝群眾開講可能還是c的寫法更好記些吧。

補充說明一下,python的for和c看上去是不太一樣的,因為python默認采取for in這種遍歷的形式。如果要當c的for來用,一般是foriin range(N)。原理是這樣的,range這個內置函數可以自動生成一個[0…9]的整數列表,然后for in會逐個提取出來賦值到i上面。

流程控制這部分,最重要的還是異常處理。老實說python的異常處理并不是很高明,只是勉強夠用的那種(這方面erlang是目前做的最好的,沒有之一)。一般最簡形式是try…except,然后是try…except…else還有try…except…else…finally。except的意思就是catch住某個異常。最基礎的異常是Exception,只要出錯了都可以抓住它。else就是沒異常的時候走的流程,finally就是無論怎樣都會有的最后一步,之所以會有這個設定是因為縮進層級會影響到作用域。簡單說,如果你在try的下一級縮進里寫了個a=1,那么在try語句的外層是訪問不到的,而finally可以解決這個問題因為縮進的層級是一樣的。

其實try語句除了用來寫這種防御性的代碼,還有一個用途就算做一些判定,比如類型比較,因為對于動態語言來講有時候你要確定一個對象的類型不一定很容易,類似isinstance這種,只能在有限個基類中做判定,無法應對那種過于未知的情況,而try就不同了,你只用確定你的假設是否正確,那就可以認為這個是足以滿足需求的。實際上,我用try比較少,反而是用raise更多。這個可能是受了erlang和其他參考資料的某些影響。

剩下的,補充一下with,裝飾器decorator和匿名函數lambda我放到后面再講。這個就是個語法糖,可以免去一個子流程過程中的臨時變量定義及預處理步驟或后續必要操作對整體流程的干擾,最常見的是open和with的結合,例如with open('target.txt') as f: len(f),然后你就可以省略掉f.close()這個過程了,一般都是類似這樣的。不過要想自己寫個with的流程,放在這里來講就有點復雜了。

然后是操作相關的語法。這里我不太想講yield,因為篇幅可能會更長。不過我想舉個斐波那契數列的例子應該就夠了。下面的代碼如果看不懂也沒關系,我會到后面的章節重新解釋一遍,現在只要關注里面的yield就好。

圖1:yield演示

然后是raise和return。return比較好理解,就是返回值,不過python里面允許忽略返回值,也就是說直接寫return是合法的,即等價于return None。return和c里面比較的區別用法就是返回多個值,其原理后面講元組的時候會補充。raise可能沒那么好理解,不過通常來講,raise是補刀用的。有時候顯式地拋出異常,更利于維護整體的代碼和業務邏輯。

倒數第三個是賦值,包括匹配賦值。Python里面的賦值和c以及js不太一樣,比如你不能這么寫:(a=(b=1))。不過你可以這么寫:a=b=1。當然,還可以這么寫來交換兩個變量的值:a,b = b,a。這個交換賦值的原理實際上是等長元組(tuple)的匹配,即在(a,b) = (b,a)的基礎上省略了括號。當然,其他編程語言里面會有用下劃線來表示匿名變量,不過python沒有這個強制設定,習慣的話也可以用單個下劃線來表示不需要的變量,比如[_,b,_] = [1,2,3]。

倒數第二個是del,雖然python自帶垃圾回收,但有時候也需要自己刪除不需要的東西,比如某個集合(set)里不需要的值。

最后是print,因為這個在python3里面被踢掉了,所以放到后面意為可選。所以如果要在這一點上兼容python2和python3,有個小技巧,就是在print和括號之間加一個空格,這樣在python2里面會被理解為打印一個元組,python3會理解為一次函數調用。

操作之后來講下結構相關的語法。首先是函數構造,用def就可以了(記得處理縮進)。

至于匿名函數,python有很多限制,不能像其他腳本語言那樣寫好幾行。類定義的話用class,允許多重繼承,不過通常來講除了用mixin之外都不推薦這么弄。導入的話用import和from…import。聲明全局變量用global,python2沒辦法聲明局部變量,這個在python3里面用local可以搞定。

基本概念

這一節會有點長,想跳過的可以先跳過,不過還是盡量看完先。

說到概念,首先是package(包)。在c里面,代碼是可以很方便的include的,這種概念很原始,也很實用。就是把一斷代碼插到另一個地方,而且為了方便,通常都是另一端代碼的開頭。js也有類似的概念,效果也很相似,不過現在大多數人寫js都不喜歡直接那么干了,講究個什么命名空間(namespace),這個也是有點用的,不過也有點多余。Python里面主要靠package來維護這么一個類似namespace的概念。其實就是學java的,然而學得很挫。建立package的方法很簡單。新建個文件夾abc,在底下建一個叫__init__.py的文件,那么回到abc的上級目錄,在這里打開cmd,輸入python –c “import abc”你會發現沒有任何問題,那就對了。Import一個package跟c里面include是比較像的,不過有點不同。比如import os之后,你可以用os.listdir去調用,這樣保留了os這個前綴,省得跟當前代碼內的函數名沖突。當然必要的時候也可以用from os import listdir這種方式來省去package name,具體怎么用,這個看應用場景。通常標準庫和成熟的第三方庫,如果名字不是很長,那么用import比較多。本質上來講,import的機制和include的機制差很多,不過不必深究,用得習慣就好。有人說python或許比較適合女生學,因為有很多包包。

還有一個概念是模塊(module),指的是可以被import的東西。這個概念包含了兩個概念,一個是前面說的包,另一個是python源文件,還是比較好理解的。

然后是類(class)和函數(function)。Python的類比較簡陋,沒有java里面的interface(接口)。另外所有的類屬性和方法(method)都存儲在類的一個.__dict__屬性里。其實在python里并不需要掌握太多使用類的技巧,只要記得不用太多繼承就好。函數的話,python是區分有名函數和匿名函數的,而且python算是強制你很多時候都別去寫匿名函數。這也就是python作者的一種強迫癥而已,不用太在意,偶爾用用lambda還是很方便的。類和函數的定位不同,如果之前習慣c,那么用函數會比較多,即便寫幾個類也可能只用staticmethod而不是property這種。如果是之前用java的估計除了一堆類還有各種類裝飾器吧。說到裝飾器,這是個很方便的語法糖,用類和函數都可以構造,看具體復雜度和各自喜好了。我這里先舉個不太復雜的例子就好:

圖2:裝飾器示例

關于對象,python和js的設定其實很多還是相似的。不過沒必要在意太多,一般在python里就是class+method的組合,類似js里面用一個對象然后像這樣{“main”:function(){}}這樣框住一坨代碼。現在普遍承認的面向對象編程實際上并沒有什么太多意義,所以盡量忘掉這個概念對迎接未來的軟件工程應該有一定的幫助。

對象之下,還有類型(type),這個很重要。不過按理說類型是比對象更基本的概念,但是一旦引入了OOP,那么不可避免會造成這樣的混淆,比如class是type還是說type可以用class定義這種新手容易搞混的問題。老實說這點其實就是python3主要想改的一個地方,那就是把類和類型設計的更規范化。不過既然我說的是Python2,那么python3之后的東西,可以自己往后再補。就像在本期前面第十八節里提到的,學點舊東西并沒有啥壞處,也方便對新事物有更深的認識。當然即便是python2,在這里我們不去深究class和type的關系,只要會用就好。

關于類型,首先你要知道,python是動態類型的,不像java那么死。這個有好有壞,此處不多做分析,只要習慣這種設定就好。然后,你需要知道就是幾個基本的類型和擴充類型:數字分整數int和浮點float(一般不用在意長度的問題,而實際上python里的float是c里面的double);字符串在python2里面是str,也和c一樣可以當不可變的字符列表來用,基于str的有unicode類型;然后數據集方面,最基本的有列表list,然后是字典map,還有元組tuple,這三個基本的之外,還有集合set,還有基于list+tuple的有序字典ordereddict等等。簡單說是這個樣子的,具體后面展開。不過在這篇指南里不會過多涉及ctypes,之前有c語言基礎的可以自己去了解下(比如你想使用些c里面的專用類型),畢竟現在大多數人之所以還用Cpython和Cython主要就是性能考慮和c語言的擴展性了。

有了前面的鋪墊,現在來具體講下常用的(或者說真正意義上的)一些基本概念(以及基本類型)。首先要講的是元組。元組這個類型比較特別,因為圓括號在python里面有很多種不同的用法,當然實際上是一個意思。比如:(1)實際上并不是構造了一個元組,而是給1加了個括號表面這是一個單元,也就是說(1)不等于(1,)。再一個,[i for i in range(2)]和(i for i in range(2))的結果也是不一樣的,前者構造了一個列表,后者構造了一個生成器(generator)。元組和列表的主要區別在于元組不可變(immutable),這個比較符合常規的函數式編程(FP:Functional Programming)的思想,前面提到的return多個值和交換變量的用法都是基于此。

列表是很多編程語言的基本概念,比如lisp。Python的列表基本可以對應C里面的數組(Array),不過python不限定列表內數據的類型,存什么都可以。另外列表的索引方法比較多樣,比如L[-1]可以表示列表的最后一個元素,L[:]可以表示列表內的所有元素,L[::-1]可以讓一個列表反轉等等(這里背后用到的也是對象的__getitem__方法加上slice,即切片)。關于列表有很多常用的技巧,而且里列表在FP里面用到比較多,感興趣的自己去了解下。

再就是字典,這個在其他編程語言里面可能叫做map(映射)或hash之類的。簡單說就是一個符合key-value的數據集。字典的key具有唯一性,且key必須immutable(官方說法叫hashable,其實意思差不多)。眾所周知,現在比較常見的數據傳輸格式比如json,里面的object實際上和dict是類似的(不過嚴格的json不允許把匿名函數當作value)。對于dict,用法也很多。不過本質上一個dict實際上就是tuple+list的組合,這個如果你調用一個dict的.items()就會吐出來一個這樣的結構。具體表現為你可以這樣解壓(unpack)一個字典的所有key:[k for k,v in D]。另外dict也可以用下標,不過python的dict默認是無序(或者說不符合存儲順序)的,所以不能用像list一樣用下標索引。訪問一個dict的value可以通過它的某個key來訪問:D[K],如果找不到的話,就會報錯(KeyError)。當然更多的情況我們不太想捕獲這個異常,所以用D.get(K)就好(這個其實是默認返回了None,如果想返回一個指定值比如2,可以D.get(K,2))。

Python的集合同dict一樣,比較符合數學規范(這個也是有好有壞)。現在的python對于集合都支持用大括號來創建了,比如:{1,2,3}。集合的操作也很多,不過個人通常用的一個技巧就是用集合去排除一個列表里的重復元素,比如:list(set([1,2,1]))的最后結果只會留下[1,2]。當然,對于這種偏數學運算的東西,比如矩陣什么的,還是用numpy之類的第三方庫比較好。

當然,最基本的兩個類型我好想還沒展開,即數(int,float)和字(str,unicode)。Python進行數運算的坑不是很多,除了除法和精度可能有些問題,其他都還好。字符串的問題倒是一開始可以坑掉很多人,老實說到今天我都不能完全避免被unicode坑一下,不過真正被坑的機會其實沒那么多的,只要用好decode和encode方法,能夠避免python2里面多數的unicode坑。

類型講完,接下來概念只要了解一下就好,比如前面提到過的生成器,這個可以用來實現惰性求值(lazy evaluation)和協程(coroutine),而迭代器(iterator)跟生成器是個很相近的東西,具體差別老實講我自己都說不清楚,不過對于python來講,如果一個類具有一個能用的__iter__方法的話,那么這個類的實例就可以拿來for in遍歷了。裝飾器(decorator)前面講過了,還有一個在構造方法上類似的概念叫描述符(descriptor)。用class定義的裝飾器主要需要提供__call__方法(通常來講python的類定義大多需要提供一個__init__方法做初始化),描述符則需要實現__get__和__set__。這個和dict的__getitem__和__setitem__是有差別的。類似的還有切片(slice),道理跟前幾個相似,感興趣的可以看官方文檔自己了解下。

還有些常見的概念我覺得有必要順帶提一下,比如:遞歸(recursive),循環(loop),尾遞歸(tail recursion),回調(callback),同步(synchronous),異步(asynchronous,簡稱async),協程,操作符(也叫運算子:operator),語法糖(syntax sugar),編程范式(paradigm),函數式編程,面向對象編程(OOP:object oriented programming),多態(Polymorphism),duck typing,模式匹配(pattern

matching),聲明式編程(Declarative),命令式編程(Imperative),馮諾依曼式編程語言(von Neumann language),組合子(combinator),lambda calculus,π演算,消息傳遞(Message passing)。

以上這些概念我不會一個個解釋以及演示如何在python里面去運用,因為很多東西是python不自帶或者不支持的,比如尾遞歸優化就需要借助第三方庫,模式匹配的話python語法原生不支持。還有一些用的比較少,比如運算符重載(override)。簡單說,關于遞歸,在python里面(stackless除外)還是少用比較好(其他關鍵詞都是打醬油的)。

讀懂代碼

OK,總算進入正題。看懂python代碼,從本篇指南的例子開始。我相信有些人看不太懂前面圖1的yield演示,于是現在我來解釋一下。圖片我就不重復插了,自己翻頁就好(順�便鍛煉一下自己的記憶力or碼字速度)。

首先這里有兩個文件:fib.py和fib_test.py,放在同一個目錄下。fib.py定義了四個不同版本的函數。fib(n)的話是原始斐波那契數列的遞歸版本(前兩個數是0和1,第三個數是前兩個數之和,第四個數是第二個和第三個之和以此類推),這個好懂,簡單說邏輯是這樣的:如果n小于2就直接返回n,n大于2就調用前兩位的fib(n)。fibonacci(max)的話用了個yield,同時還用了個變量n來計數,算是標準的生成器版本。簡單說邏輯是這樣的,給定一個個數上限max,第一次調用的時候,yield a,即為0,后來a變成了1,b變成了2,也就是下次調用函數的時候yield的就是1,以此類推。后面的兩個函數F1和F道理是類似的,只是沒有用n來計數,F1也能生成數列,不過在個數控制上會存在問題(你會看到底下輸出的時候只有第三行是輸出了四個數)。fib_test.py是用來測試fib.py的,第一行是導入了所有fib里的函數所以在fib_test里可以直接調用。第三行就是一次list comprehension了,這個效率很低,因為n>3之后每次fib(o)都要遞歸一次。第4,5行也是構造一個列表,方法一致。第6,7行可能不太好理解,因為用到了匿名函數lambda。先從右往左看起,F()調用后生成了一個generator,然后傳遞給了lambda,匿名函數里就是調用三次__next__方法的意思。但你不能直接在lambda里面寫F().__next__(),因為這樣每次都會F()重新常見一個生成器。

接下來解釋一下圖2里的裝飾器。文件結構和圖1的例子是類似的,不再解釋。這里有兩個裝飾器,一個是函數D1。另一個是類decorator。先看裝飾器做了什么,第11行前面的一次echo(T)調用就是print出一句第4行說的文本,這里是給參數T做了強制類型轉換的。第12行分號前面是用D1裝飾后的函數e2(T),輸出結果的變化在于原來echo(T)的后面多了一句By: D1。類似的,e3是用decorator類來裝飾過的echo,區別在于e3是在調用echo前多輸出了一行。簡單說這兩個裝飾器的作用都是只是在給做原函數做類似打補丁的事情,當然裝飾器的復雜用法也有,比如用來模仿模式匹配的效果。現在來講基本原理。其實構造的原理是這樣的,我們先看右邊的deco_test.py里的第9行和左邊deco.py第7行開始的class定義,這個是裝飾器的本質。echo函數作為decorator實例構造的參數傳到了__init__方法里,然后綁到了實例自己的fn屬性上。然后在實例調用的過程即__call__方法中,先于self.fn調用了一句print。函數構造裝飾器的方法也是類似的,D1里面的W函數(一般叫做wrapper)實際上就是個包裝,最后用return的W來替代原函數。而@語法糖實際上就是做了個同名函數替換的過程,即右邊第6、7行可以理解為:先定義好一個e2,然后讓e2 = D1(e2)。

以上差不多是前面代碼的講解,如果搞不懂的話自己寫一遍試試,或者Google一下。回顧前面我寫的代碼,如果你了解pep8的話,可能會替我的人身安全擔憂。是的,我之所以這么不符合規范地寫python代碼的用意,是在于讓大家了解python的語法其實沒有那么死,至少沒有傳說中那么惡心。你可以用逗號,用分號,用反斜杠,或者寫一堆lambda,甚至用type函數來定義類,只要不影響代碼的組織結構和debug,我覺得都是可以的。

當然,就這點代碼量不足以認為可以讀懂大多數的python代碼,所以這里我覺得有必要多加點示例。首先是python自己的標準庫。首先舉個比較簡單的例子:

圖3:datetime模塊源碼概覽

圖中上半部分的代碼是一次調用標準庫的示范,即調用datetime.datetime.now()方法。假設你不知道datetime這個模塊怎么用,最簡單的方法其實就是去查文檔或者網上找資料。稍微原始一點的,可以在命令行里面調用help(datetime.datetime.now)或者dir(datetime.datetime)這種(如果用ipython?qt console的話在鍵入過程中會帶有提示的),更原始的就是上圖這種查看源代碼的方式了。

但是具體來說,怎么找源碼呢?最土的方法,自己在python安裝目錄找(通常就在lib文件夾里),或者,借助操作系統或第三方軟件來搜(我偶爾也會用everything來找python的模塊文件),又或者,借助編輯器/IDE的功能,這個emacs / sublime / pycharm都有,不過個人還是習慣在pycharm里面翻源碼:

圖4:pycharm下查看第三方庫的源代碼

簡言之,對于想快速上手python的人來說,anaconda+pycharm+zeal無疑是最佳組合。

上述所講主要是讀python代碼的方式,沒有講到具體要點。其實要讀懂python代碼不難,通常(對于一個有規模的python項目來講)情況下,首先,有文檔的先看文檔,因為文檔一般都有api reference這一塊,這樣可以快速理清目標的代碼結構,當然如果沒有文檔的話,就靠pycharm之類的。通常大部分project都會帶有一部分測試代碼,通過測試代碼來反查也是一種思路。當然,以上思路對于某些具體的代碼片段并不管用,尤其是某些算法題。通常看不懂python代碼有兩種情況,一是不知道整個代碼是怎么工作的,二是看不懂這里面寫的是什么意思。前者基本上方法和思路已經說了,現在來講下后者。先舉個簡單的例子:

圖5:單行代碼示例

上圖的單行代碼如果看不懂,分解就可以了。str().strip()會去掉字符串兩端的空格(因為空格是默認參數),split()會以空格分割字符串列表,最后那個[::-1]前面講過了,一個簡單的逆序方法,最后‘’.join把前面的列表合并成一個字符串。

上面這個例子還是很好懂的,因為涉及的冷門技巧不多。現在再換一個:

圖6:leetcode代碼討論概覽

老實說,對于上面這種代碼,我不指望一下就能看懂,其實,對于多數情況,只要會用會改就可以了。即,讀懂python代碼的關鍵,還是要會用先,再是改寫,讀懂是其次。

本來關于讀代碼,我覺得講這些就差不多了,剩下的可以多練習練習,找些簡單的項目源碼看起。本來有想過舉些稍微有點代碼量的實際項目做例子的,但是感覺單講源碼分析的話會寫好長,也就不好詳講,最后一個例子我們來簡單分析一下某socks工具的源碼:

1. 首先我們要把源碼下載下來,這里只需要git clone 一下就可以了:

2. 用pycharm打開目錄,上來先看一眼setup.py以及文件結構:

這一步是為了弄清楚package的依賴關系(不過這個項目的install_requires是空的所以也就沒什么依賴了),有些項目可能會把這部分抽離到一個requirements.txt里面。然后我們還可以看到entry_points里面有兩行,對應生成兩個可執行命令console_scripts。

3. 接下來就看項目的具體用途而定了。如果是一個工具型的庫(比如SQLAlchemy)那么就從__init__.py入手,當然也有人不喜歡在__init__.py里放東西(比如django),那就對應的各找各咯,思路是一樣的,找一個入口。而對于非工具類的(比如我們現在看的這個),也有對應的入口,那就是它的執行文件:

然后再一步步深入,比如具體上面的tcp_server要怎么實現。

4. 最后就是改動代碼和反復調試了,這里截圖演示不了,就略過了,其實是最關鍵的一步。不過沒關系,大家可以當作聯系。不過上面這個例子的代碼量并不大,如果覺得這個代碼量不夠塞牙縫的,可以換一個:https://github.com/Pylons/pyramid

以上都是比較基礎的分析方法,沒有借助到pycharm之類的IDE獨有特性。

最后補充一下。要讀懂代碼呢,基礎是很必要的,而基礎之中的基礎就是規范了。說道規范,首先是注釋。python的注釋分兩種,而且差別其實還挺大的。注釋也有很多用法,可以方便調試,可以寫文檔,可以做文檔測試。不過總的來說,規范只有一條,那就是文檔注釋用三個雙引號(以及前面提到過的四空格縮進),不要用單引號,具體為什么,可以自己留到后面去思考,也可以參照pep8,這里不解釋。

代碼調試也是基礎,新手上路,首先要習慣看trackback異常。單條異常日志要倒著看,進階之后,可以自己試著用日志來替代調試過程中臨時寫的print。往后,用ide的debug功能或者各種debug工具(gdb、pdb、pudb等等),或者自己手動監視locals(),再往后,也可以引入inspect和自省(interrogation)。當然,個人目前還介于print和log之間的位置,感覺基本夠用了…

再就是熟悉標準庫,需要的時候做點筆記也是應該的。雖然對于大多數人來講每星期寫點技術總結很困難(包括我),但試著寫寫還是很有幫助的,無論內容的好與壞。關于讀代碼的部分就講到這里。其實從注釋開始,讀代碼和寫代碼之間的章節界限就已經模糊了。

寫代碼

這里我只說一條原則:若無必要,勿增實體。或者反其道行之。不過由于python的語法限制,通常還是精簡比較好。如果是元編程吐出來的python例外。

我記得有些c語音或java書會教你先不要用IDE,用記事本之類的文本編輯器寫起,這個其實是有一定道理的,然而,這個道理并不太適合java,因為java的大部分代碼并不能在一行之內搞定。當然,很多時候單靠人來糾正代碼里的錯誤還是比較費時間的,于是就有了pyflakes、pylint之類的第三方工具。另外,說到文本編輯器,windows自帶的記事本并不是一個很好的選擇,如果覺得sublime比較重量級(?),那么notepad2-mod / notepad++之類的或許比較適合你。

當然,我還是假定大家可以先試用一下sublime,因為這個文本編輯器的擴展性還可以,且不如emacs那么難上手。一開始寫代碼,對于完全沒有編程經驗的人來講,難免會有語法錯誤(syntax error,indentation error等等),這個還是先適應一下比較好,不然如果一上來用pycharm,結果碰到一個只有vim還沒有安裝權限的linux虛擬機,那就準備哭吧。關于工具的選擇,無論是軟件(以上)還是硬件(ssd或機械鍵盤),到頭來還是看個人需求。

除了語法錯誤,還可能碰到很多其他的錯誤,解法嘛,一般先自己思考,不行就網上找找。當然,養成良好的代碼組織習慣之后可以避免一些錯誤的發生。比如有的時候一個分支邏輯判斷寫太長,那就最好拆開來,封裝涉及的實體比較多,就不要用太多繼承。

說寫代碼的話,差不多就這樣了。畢竟編碼(coding)在我看來是一件很枯燥的事情,建議有目的性的寫或改,比如你喜歡或有意向搞數據分析,那就不要開多一個窗口去折騰web框架。

寫代碼的風格也是因人而異的,有人喜歡上來寫大綱一樣先把結構列出來,有人喜歡編寫邊調試。一般來說,對于較大的項目,后者比較實際點。這里說的寫代碼風格和前面提到過的編程范式不是一個意思,編程范式的話有很多種分類,OO還是FP,命令式還是聲明式等等。個人偏向于聲明式+函數式的組合。當然這里說到優劣,也還是見仁見智的。比如我雖然習慣函數式,但并不死磕純函數無副作用這些,畢竟實用就好。總之,接觸的編程語言越多,自己的編程范式會逐漸趨于穩定,這算是從我個人經歷總結出來的吧。

最后再補充點相關知識。如果需要長期編寫一個項目,無論是否團隊協作,最好還是引入版本控制系統(VCS,version control system),方便做變更日志記錄。比如今天做了哪些改動,還差哪些沒實現等等。雖然這不是VCS的標準用法,但也不違反規范。一般推薦用git和hg。hg的話比較適合那種單人玩一玩性質的項目,因為配置很簡單。如果一開始定位就比較高的話,還是用git吧,這個基本上已經成為業界標準了,省得以后還要遷移。

另外,不要懶得寫文檔寫測試,哪怕只有一點點。雖然很多時候自己也不寫測試…

好啦,回到本小節最開頭那句話,其實就是控制復雜度的另一種表述形式吧,或許這樣說會比較好懂一點。

還有,這里可以順便留點簡單的作業題:

1.寫個標準的冒泡排序(可選:用遞歸實現)

2.用一行代碼,把當前目錄下文件名中的某段固定字符串批量刪除掉,長度越短越好。比如:abc-xyz.mp3和bcd-xyz.txt中的xyz。

誤區

這里主要講些常見的關于python的誤區。首當其沖是python2和python3的爭執。其實現在python3都到3.5了,隨著新特性越來越多,守舊的人也只會繼續守下去,比如我,不過個人同樣支持python3的發展。之所以不用python3是有原因的,如果你開發的環境需要用到很多歷史悠久的第三方庫,那么用Python2通常要保險一點。如果單純是運維的話,一般沒問題,因為多數第三方庫存在的問題都出現在那些關鍵特性的變更上,比如字符串。當初碰到過BeautifulSoup4在3.4里面處理的結果和2.7完全不同情況,最后實在無解了只能把部分方法覆蓋掉敷衍了事。現在python在web領域的地位已經受js和ruby沖擊得所剩無幾了,除了爬蟲代理各種小工具各種成熟的庫以外。而在科學計算和數據分析領域,python這幾年倒是增幅比較大。換句話說,工具總是要適應場景的。

關于OOP,python雖然也號稱一切是面向對象的,其實并沒有那么純粹。當然個人認為還是不純粹的好。習慣java的人可能覺得python里面沒有interface會有點奇怪,不過要說python沒有interface也不完全對,只是沒有嚴格的實現而已。有個第三方庫叫zope.interface,可以滿足大部分需求(雖然這個庫的主要功能不局限于此)。一般的python項目需要用到它的機會不多,也只有在工程量比較大情況下才會用到,比如twisted這樣的。有人可能之前看到zope就覺得臥槽這是什么鬼還能用嗎,不過這又是另一個誤區了。

續上。很多人覺得python的所謂的哲學就像《unix編程藝術》里面描述的那樣,差不多可以用simple is better來描述。其實這是一種片面的認知。首先我覺得編程語言根本就沒什么哲學概念一說,用比較形象的詞來說,只是一種虛無縹緲的情懷罷了。具體到python的話,只要它存在著c擴展,那就不可能simple下去,只能一味的掩蓋罷了。所以真正要用好python,必須要直面python的歷史。而講到歷史,這里有必要概括性科普一下zope。

Python的早期發展和zope有千絲萬縷的聯系。Python的作者GVR在1994年發布的1.0版本,那時候還在CWI(Centrum Wiskunde & Informatica),后來去了CNRI(Corporation for National Research Initiatives)。2000年左右,在發布了2.0之后,pythonlabs的一席人加入了Digital Creations,也就是Zope公司的前身。2003年,在完成python2.3之前,GVR離開了zope,但當初那些python的核心開發人員不少還在這家公司。好吧,其實zope是一家公司,也是他們做的一套web框架體系的名字,自然也是最早的python web框架之一。

Zope的大致思路就是仿當時的J2EE,把python當java使。這個其實是可行的,而且效果還不錯,但是社區的大多數人都不太接受這種又帶接口又是xml的玩法。Zope2可能接受的人還有,畢竟很酷炫還實用,直接能在瀏覽器里面修改業務邏輯。但zope3反而更激進了,于是到最后zope3也只相當于是個半成品。Python社區里現存的和zope相關的,還有人記得的,估計就剩plone了,但這個相對還是太復雜了,現在的人一般搞cms基本都不會考慮它。說到Web框架,中期冒出來的Django現在的普及度就很高,它是仿ruby on rails的。后期的框架都是比較輕量級的,諸如flask,tornado這些。實際上zope這一支還沒死,zope3之后有了repoze這個項目,把zope的遺產解耦了,到現在還有人用的主要就ZCA(對應zope.interface)、ZODB和traversal這三個了。Repoze里面有個web框架叫bfg,后來跟一個中后期web框架pylons合并了,成了今天的pyramid(我主要用的就是這個)。雖然pyramid相對django來說可能沒那么方便快捷,不過熟悉的過程中倒是讓我對python的發展有了更深刻的認識。

科普zope就到這里,我想說的其實只是希望做選擇的時候還是盡量盲從(沒看錯,這樣省時間),但還是要廣開思路,不要局限了自己的視野。Pyramid是我覺得python里面最實用的web框架,但限于歷史背景,很多人都對這個代碼量巨大的框架有一種畏懼心理,這大可不必操心。經得起時間考驗的開源項目就這個好處,實在不行了自己改一改就好。

關于python的語法,誤區不多,縮進、分號都不是什么大問題。坑人比較多的還是邏輯判斷,比如前面有提到過的is語句。if語句也是,有時候省略一些描述覺得像if a這樣會省事,但需求改了之后可能限定a的條件可能就是另一個意思了,因為if語句默認None和False是歸為一類的,還包括空列表等等。

關于python,我覺得最大的誤區可能還是認為什么都可以用python來做。其實也不是不可以,但多數情況這是不科學的。我舉個例子,VCS里面,現在主流的三個有SVN,Hg和git。豆瓣早年覺得hg是用python寫的,應該好擴展吧,結果最后還是把代碼庫整體切換到了git上面。有時候就是這么現實。類似的還有個例子,現在自動編譯代碼或者部署之類的,多少會用到makefile,但是python歷史上出現過buildout這樣的東西,就是完全靠python實現項目的部署等一系列操作。我覺得這個沒有流行起來是也有原因的,既然makefile用的人那么多也不難學,為何要多了解一個更復雜的體系呢?

還有,有的人覺得有了pip就可以不用easy_install了,實際上這么講也不科學。而實際情況,easy_install要比pip好用的多。因為多數環境下你根本不需要用到uninstall這個功能,而且,現在的virtualenv都是一次性的,出問題了就重新建一個,也不費事。

效率問題可能也有很多人在意,但也有很多人不在意。而我覺得,不把效率當回事才是真正的陷入誤區了。有些事情,能用一個for循環何必用兩個呢?可以硬編碼的,何必要放到數據庫里面?所以說,環保節能,要從我做起。

設計模式也是常困惑新手的一個問題,python到底需不需要類似java里面那樣的設計模式。其實是有的,但不多,一般只要搞懂adapter和factory就夠了。認為需要完全照搬或者完全不需要的,那都是走極端。

另外,有些人覺得python在windows下開發會很痛苦,其實那只是一些沒用過msbuild的人的臆想。當然,在windows系統上摸索編譯c擴展是一件很累人的事情,這里給個參考,大致的流程就是:裝好visual?studio(2008以上的express或2015社區版都可以),還有系統對應的windows sdk(一般來說win7sdk比較通用);然后打開vs的命令行(分64位和32位,這里以64位為例),設置兩個參數( set DISTUTILS_USER_SDK=1和setenv /x64 /release?),然后再用python setup.py就可以了。

而說到誤區,我覺得最嚴重的,可能是關于python所謂的膠水語言的這個定位。很多人以為python作為膠水語言是為其他各工具集之間建立橋梁,實則不然。我覺得膠水語言的本質,是用來縫合歷史遺留問題與當今環境之間裂隙的,說簡單點,就是用來彌補一些類似c語言這樣的舊工具的不足之處,以便讓這些舊工具能適應新時代的需求。

最后,請不要忽略測試代碼的重要性。再次強調。但,是不是說代碼測試通過了就一定管用呢?這個還看你的測試覆蓋率,但,即便是100%的覆蓋率,也不等價于你的代碼就沒有任何問題了。這里沒有絕對的因果關系,只有可能和不可能。以上內容主要是對新手而言的,如果你覺得這些誤區你都了解,那么就該看一下沈崴當年留下的幻燈片《python編程藝術》里面關于誤區部分的深入探討了。

參考資料

本來想在這里留一些參考資料的,但是想想,除了那些文檔鏈接以外,好像也沒什么特別的。找東西,能用google就google吧,不能用就先翻過去。以下可以算作附錄,也就列舉寫python相關的第三方庫和工具的名字:

數據/計算:sqlite、bsddb、mysql、sqlalchemy、redis、mongodb、zodb、numpy、scikit、pandas、PIL、matplotlib、openxml、cython、pypy

實用/基礎:anaconda(conda)|ipython(notebook,

kernel)、pywin32、setuptools、virtualenv、pip、buildout、mr.developer、nose、mock、uncompyle、pdb、pudb、fn、toolz、patterns、pyrsistent、pp、multipledispatch、gevent、pyqt、pygments、sphinx、you-get、sh、zope.interface

Web /網絡:django、flask/jinja2、bottle、tornado、pyramid、zope2、webtest、beautifulsoup、requests、twisted、scrapy、httpie、oauth、lamson、shadowsocks、celery、rabbitmq、fabric、saltstack、sentry、planet、pelican

暫時就想到這些,我書讀得少,見識不廣,有些庫也只是道聽途說,和web開發不相干的就更不知道了,以后有好東西再慢慢填充吧。順便科普一下pypi(python package index),這個相當于node.js里面的npm,用easy_install安裝東西,默認都要先在這里面找一遍。當然,如果自己用東西打算開源,除了在github上放代碼,也推薦在pypi上傳自己的包。

新手路線

# 簡書有字數限制,此章略去絕大部分

Ok,回到我自己的新手路線。除了文檔,其他還比較有幫助的,就是一些陳舊的資料了,比如limodou(李迎輝)的博客。他是文本編輯器ulipad以及web框架uliweb的作者。記得他有用過好幾個博客,donews的比較早,百度空間也有,后來百度空間停服了,那部分資料估計現在也找不到了。Stackoverflow上的問答資料也幫到過不少忙,即便像pyramid這樣冷門的框架,上面依然能看到一些優質的問答,其中還包括一些web框架作者的解答,總之很多很多。然后還有其他一些國內的早期python人物,比如前面提到過的沈崴(郵件列表里人稱沈游俠),他的網易博客也留下了不少有用的文章,當然最具代表性的還是他那個《python編程藝術》的幻燈片。一開始看的時候心里想這特么什么鬼,后來過了兩年回過頭來看才覺得這人當年是何等的牛逼。

同時期的我記得還有賴永浩和潘俊勇。老潘當年推zope幾乎是不留余地,可惜我開始接觸zodb的時候,已經是N年后的事情了,不過當年留下的一些翻譯文檔還是有些幫助(另外還有EryxLee寫的一些pyramid教程),不知道現在還能否找到。科學計算方面,當年有個張若愚,還出了本書,雖然有些過時不過看著也挺不錯的,貌似曾經說要出第二版,不知道情況如何。同時期相對年輕點的,還有清風,張沈鵬(人稱教主),剩下的有影響力的我記著好像就沒幾個了,也許現在還活躍在知乎或類似的地方打打嘴炮,好像也沒啥了,不少也早轉方向了。

當然這些國內的python大牛,我記得好像都是從啄木鳥社區和python-cn的郵件列表找到的。而說到啄木鳥社區和python-cn的郵件列表,由不得不提一下國內python圈里面廣為人知的大媽:zoom.quiet。此人對早期國內python社區的發展做出了很大的貢獻,雖然有些方面的意見不敢茍同,但其付出是值得肯定的,包括好幾次pycon的籌辦工作,雖然pycon沒幾屆辦的特別好的,但也算是挺不容易的吧。國內的Pycon,老實講我都沒太明白它的定位,雖然不能跟國內的ruby conf比,但或許還是有些存在價值吧。

我記得前面開始水zope的時候有講過:歷史很重要。是的,我的新手路線離不開對python歷史的各種花式挖墳,國外的也好、國內的也好,基本都被我扒過了。而挖python歷史的過程對我個人也有不少幫助,因為你會意識到某種歷史的局限性,例如你會漸漸地會明白python3的各種紛爭以及未來python的發展趨勢。

我覺得可以一句話概括Python的宿命:領導者是對的,然而并沒有什么卵用。這個不僅體現在python的core team,比如當年做出py3k決定這件事情。我也覺得搞python3是對的,但是,不向下兼容的話,那也只能等歷史來完成這個漫長的過渡過程了。同樣的,在國內python社區也是這個問題,管事的那幫人想法也是對的,但是,現在這個年代堅持用著google郵件列表真的好嗎?自己搞一個像erlang一樣的獨立郵件列表或者ruby-china一樣的官方論壇會死啊?

誰知道呢,我也不是沒跟人提過這個事情。而,整個學習python過程中我最不爽的問題就是這個,本來好好的一個python社區,隨著09年天朝局域網體系的確立,變得分崩離析。如果不是因為大部分人上不了google,或者說非gmail后來根本收不了里面的群發郵件,v2ex后來也不會有那么多玩python的人在里面。我也知道,國內還有個水木清華,還有個python貼吧,但說真的,最早那一批玩python的死守google郵件列表的結果就是必將導致python社區的斷層,而歷史將無法得到延續,更別提文化的傳承。

如果要我給他們提個建議,也很簡單:去google化,接地氣;面向大眾,走向中立。今時今日的google早已不是曾經的google了,python在腳本語言中的地位也開始受到更多的挑戰,做出些艱難的決定,有時也是必要的。當然,即便python在中國做不活社區,我也覺得沒啥,畢竟相濡以沫,不如相忘于江湖。而我最初喜歡python的,也是這種感覺。

寫這篇東西的用意,一方面是希望能幫助到新接觸python的人,或者學習過程中遇到了跟我類似問題的人,能夠有個參考指南,不至于犯太多同樣的低級錯誤。雖然很多時候犯錯是無可避免的,于是真正有點用處的,也只是讓很多新人能夠了解一部分python在國內發展的前世今生。雖然我所說很主觀不完整也不一定對,但也是某種角度的參考吧,畢竟國內很少有人像我這樣憑空扯淡這么多字數的吧,囧。

其實曾經也有人跟我有著類似的想法,或者說我之所以有寫這個打算,完全是受前人的影響。在國內python社區發展的比較好的那個年代,那時候google還沒被墻掉,有一本挺不錯的書叫《可愛的python》。一開始我以為這是一本給新手看的書,然而我錯了,可能當初大媽編輯的時候也覺得書的定位應該偏向新人,結果效果恰恰相反。這本書一開始我看的時候是云里霧里,因為我用的主力系統不是linux,有些東西沒辦法實操,加上章節安排有段混亂(比我現在寫的這個還混亂),讀起來也費勁。而且,我至今沒搞懂那個CDays是什么意思。后來再看的時候我又覺得,里面很多東西都過時了,好像除了懷舊并沒有什么其他用途。不過再后來我就發現讀這本書是一個了解國內python歷史的絕佳途徑,而且里面的一些小貼士(書里寫作作弊條,cheatsheet)也挺實用的。

當然,很多python書籍還是不錯的。挑選一本好書要看很多方面,封面設計、排版、標題、厚度、作者經歷、譯者水平以及出版社也都包括在內,看多自然就會挑了,沒有捷徑。

真·新手路線

首先我想提一下圖形界面這一塊,先聲明,個人不建議拿python搞GUI。你會發現,在前面的參考資料部分,我都沒有提到wxpython。wx還是有不少人在用的,而我只是象征性的放了一個pyqt。這么做或者說不推薦GUI開發時有原因的,畢竟是python比較明顯的一個雞肋領域。如果真要弄,自帶的tkinter基本就夠了,pyqt我覺得學習成本不亞于twisted。而安卓方面,雖然現在有個叫kivy的項目,GVR也推了,然而(github上的關注了居然比pyramid還低)。所以,不要誤入歧途。講真,如果要搞,現在c++/java/.net甚至js都比python要實在。

然后是科學計算和數據分析領域,這個是目前python比較火的一個地方。如果你對這個感興趣,那可能就會明白我推薦安裝anaconda的用意。前面提到的有些庫也是這個領域常用的,比如numpy / cython / matplotlib / pandas等等。但畢竟沒接觸過這個領域,所以其他有用的東西我可能還沒來得及接觸,僅僅是有耳聞的那種。不過ipython倒是比較常用,因為這個不分領域,qt console能爆官方命令行十幾條街,用過之后就不愿換回來了。不過據我一些在公司里做DA(數據分析)的同學講,其實真正用python的時候并不是很多。

然后是網絡這一塊,python還是有一定優勢的,因為庫比較成熟,比如twisted這種。雖然twisted也跟zope一樣很多人見了就怕,實際上也沒那么夸張啦,一旦習慣了ZCA這種設定,再多的python代碼看上去都不會覺得太惡心。爬蟲方面,python也是比較成熟的,抓站之流比較出名的有scrapy。網絡安全方面我不是很了解,感興趣的自己去google一下。

Web開發這塊,水比較深,我接觸的也最多,于是打算放到后面來講。一般上來都會選個框架,主流的是django,選它不會錯,就看習不習慣了。次一點的有flask和tornado,在國內都有些創業公司用在生產環境上了。Bottle/web.py也有人用,不過相對比較少。而且bottle其實往深了講,適合入門但并不太適合新手作為主力長期使用。其他更冷門的框架也有人用,比如web2py,比如pyramid。

我這里可以簡要概括一下幾個框架的主要特點:首先是django。Django最開始是仿rails這個應該都明白了,但是概念上有些許不同。比較適合快速開發,用起來也是簡單粗暴。現成的擴展很多,比如你想給自己的項目加個sentry的支持,一搜就能找到django-sentry。而且整個工具鏈都很齊全,數據庫遷移(db migrate)什么的也已經很成熟了。但是,選擇django意味著喪失了一定的可定制性。因為實際上你不肯能真正去改動django的源碼,太多了,10M的大小啊。而且,即便你想給django修點bug或者加點新功能,也不是那么簡單的事情。

相比之下,輕量級的框架就容易些,比如flask和bottle。用flask的人多主要原因可能是集成度比較高且擴展多。至少,flask記成的自家模板jinja2要甩bottle的原生模板幾條街。而Bottle的買點無非是單文件import,這個其實也是最大的局限性。Flask的問題在于擴展多了,感覺和django也沒啥區別,而且集成度可能還沒django做的好。我就記得以前用flask的時候,加上flask-alchemy老出錯,但是自己手動接入sqlalchemy一點問題都沒有。

Tornado這個框架相對比較特別,因為說它是框架其實并不嚴謹。其實它應該是web.py的威力加強版。目標和django一樣也是大而全,但是整體架構還算輕量級。因為我沒試過這款,不太好對這個框架做過多的評價。優勢可能是集成前端交互比較方便,還自帶了server端的功能,應該來說是最適合新手的一款。缺點,也許是異步回調的一些寫法不太符合python的風格(實際上也可以用同步邏輯寫)。

高度集成的框架里有一個極端叫Web2py,被人吐槽的很多。然而做些小站點也沒有傳說的那么糟糕,你看前面提到過的張若愚,他不照樣用的很舒坦。

我的選擇是pyramid,當初選擇的理由是我觀察到python的web框架的發展呈現出一個整體發散的趨勢,而pyramid在那個時候是由兩個框架合并過來的(即repoze.bfg+pylons),這一點我覺得挺有意思。深入了解之后,我發repoze.bfg原來繼承了zope一脈的traversal功能,這個我挺喜歡的,還有chameleon模板等等。我比較喜歡這種有實力的項目,即便它看上去不那么出眾,但是感覺很適合自己。總之,每個人都有自己的喜好,但有時候適合自己的未必適合別人,所以放到工作上,總有些東西需要去適應和妥協的。

Web開發這塊比較麻煩的,如果不是在大公司里,不可避免的要牽扯到一部分運維的工作。比如環境和代碼部署啦,自動化測試啦,數據庫維護等等,不過我覺得最要命的可能還是前端。現在部署的花樣比以前多多了,docker是13年左右開始冒出來的,現在用的人比以前要多不少,這個相當于一個系統級別的virtualenv。我還沒怎么正式用過,據說效果還可以。代碼倉庫基本上都一律用git了,除非公司用的svn之類的比較難遷移。CI(Continuous Integration)方面,我沒怎么試過,只知道有那么些工具還不錯,比如buildbot / Jenkins / travis等等。運維方面,用過的也就fabric,saltstack據說還不錯,不過也沒試過。

數據庫方面我覺得可以分出來講講。很多人剛上手web開發比較頭疼的可能不是前端二是sql。其實呢,sql沒那么惡心,習慣就好了,而且現在也還有很多nosql的選擇,也很成熟,比如mongodb和redis。不過關系型數據庫還是廣泛應用的,出來混,遲早要還。主流的還是mysql,小型的可以用sqlite,國內用oracle和sql server(t-sql)的也不少,不過個人比較喜歡postgresql,其實初階水平來用的話,差別都不是很大。但具體到開發,sql還會涉及到數據庫遷移的過程,如果用django你就輕松多了,其他的話,可能還得借助sqlalchemy+alembic的組合,或者,自己手動alter table吧。

前端之所以說頭疼,是對于類似我這周單干的人來講的。前端的工具和技術更新的快,搞后端的基本是跟不上節奏的。這倒不是重點,搞前端的知識儲備和經驗積累可能比大多數搞后端的人預估的還要多得多。而且,還需要一定的設計水平。很多搞后端的就是喜歡偷懶,以為用個bootstrap就可以省去前端設計的工作了,于是乎曾經好長一段時間,你都會看到很多網站的按鈕都長這樣:

圖12:bootstrap2中文文檔(局部)

所以有時候太偷懶也是不行的。不過還好現在boostrap效果比以前簡潔了許多,沒那么強烈的違和感。現在前端用到比較多的工具,我所知的有:node.js、gulp / grunt、coffeescript / typescript、angular.js / react.js

/ vue.js、jquery / lo-dash、d3.js / three.js。其他的沒列出來的說明名氣還不是很大。由于自己的前端水平也不是很好,這里就不細講每個工具的個人喜好了。獲取前端資訊的方法有很多,關注點新聞站點,水下知乎,刷下微博,搜些好文章,都可以的。當然最重要的還是參考與實踐結合,這個道理無論前后端都是相通的。

Web開發方面差不多就這些,現在大部分都是后端提供些api,前端分離,手機應用也調api或者干脆用混合應用(html5 + native code)。等項目架構稍復雜點,不可避免的會引入消息隊列、集群、冗余、周期性任務計劃以及性能優化等等,有時候還不得不做點seo之類的雜活,總之是個深坑。而游戲的水更深,所以我就沒太多能講的了,只好一筆帶過了。現在用python做游戲的還真不多,大多都轉lua了。而聽過且比較出名的可能是eve,不過用到的好像是c++結合stackless python。

# 略

后記

# 同理,略

全文 pdf 在此 -> 關注公眾號 “ 無知紅 ” 回復? “?簡明python指南 ” 即可獲取下載鏈接

擊運行)

作者還在找工作,目前沒有收入來源; 每一秒贊助,都可以幫助并促使他更快地寫出更多更好的內容

總結

以上是生活随笔為你收集整理的简明python指南(预览版)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。