從C語言開始,本身陸續學習了C++/Java,可是自從研究生作畢設接觸Python以來,就愛不釋手,再也沒有動力嘗試其餘語言。然而慚愧的是,因爲一直從事科研工做,由於不多關注代碼規範性與代碼效率,致使本身以前論文所作實驗代碼可讀性極差。故而忙裏抽閒得一半日,粗攬《Python編程之美》,收貨頗豐,故而重作於屏幕前,權當整理記錄。因爲全書於己涉及知識點很多,故而僅挑選當前急用者梳理之。python
Python的一大優點就是具有優秀的可讀性,而這基於一套較爲完整的公認編程規範。這裏建議全部初學或使用Python的同窗,能夠先從PEP_8入手,其中包括了命名、空格、換行以及函數參數等多個最經常使用最基本的編程規範。編程
以本身爲例,一般命名變量都採起大小寫組合的形式,如一個表示用戶特徵的變量,一般會命名爲Users_Feats_lst,而閱讀了PEP_8以後才發覺這樣寫十分不美觀,致使讀起來十分混亂,推薦的命名規範是:閉包
上面是本身初讀完PEP_8馬上就用上的一點小規範,感受很實用。所以建議你們在開始Python前抽出十分鐘先讀讀PEP_8/20,後者是對於前者的一個擴充升級,不過我建議初學的同窗先從8開始就能夠了,逐步學習便可。app
這部分咱們就開始梳理感受最實用的規範了。學習
Python中提供了同一功能的多種編碼實現方式,那麼越明確越簡練的方式就越推薦。判斷代碼寫得是否優雅的一個經驗法則是:其餘開發者是否能夠只閱讀函數的首行與末行就理解函數的做用。編碼
Python通常要求一行僅寫一個語義句,避免多步處理寫在同一行;固然,若是一個長參數函數能夠在函數部分斷行,如使用反斜槓**或者小括號。.net
當遇到多狀況的if-else判斷時,每每能夠在每一個判斷後返回結果,然而這與具備多重出口的迷宮同樣,會下降可讀性,故而通常要求函數寫成僅有一個返回return的形式。代碼規範
對於和邏輯變量以及0比較的狀況,相等性檢查所有建議替換爲直接使用if語句,以下述狀況就推薦2)的形式。code
1)if flag_0 == True: pass 2)if flag_0: pass
通常而言循環操做列表時咱們都喜歡使用如下方法,如從下述列表中篩選出大於等於4的元素:
a = range(10) b = [] for ele in a: if a > 4: b.append(ele) else: continue print b
然而,如今咱們要推薦一種更爲簡潔優美的方法:列表解析
a = range(10) b = [i + 2 for i in a if i > 4] print b -->[7, 8, 9, 10, 11]
即,咱們只要遵循格式[ele operator | ele from where | ele condation]便可,進一步地,上述代碼結果說明不只能夠設置篩選特定條件的元素,進一步還能夠對每一個元素進行運算。
固然,若是上面的公式你感受彆扭不容易讀,那麼也可使用一樣功能的函數,只是篩選對應filter(),運算對應map(),其中filter函數返回篩選條件爲True的元素組成的新列表,而map函數返回函數操做結果組成的新列表。
c = filter(lambda x : x > 4, a) print c -->[5, 6, 7, 8, 9] d = map(lambda x : x * x, a) print d -->0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
解包操做主要用於已知列表或者元祖長度的狀況下分配元素,其通常通用公式爲:
taget_1, taget_2,...,target_N=長度N的列表或者元祖
須要注意的是,僅在Python 3.0以上版本中,才支持可變目標參數的解包(Unpack)
你可能會想這還不簡單?可是其實很容易犯錯,咱們先給出總結的規律:
# case 1 four_nones = [None] print four_nones * 4 -->[None, None, None, None] # case 2 four_nones = [] print four_nones * 4 -->[] # case 3 four_nones = [[]] * 4 print four_nones -->[[], [], [], []] four_nones[0].append(1) # still be list, so save the copy attr print four_nones -->[[1], [1], [1], [1]] four_nones[0] = 2 # changed to be integer not list print four_nones -->[2, [1], [1], [1]] # suggest format: 列表解析 four_nones = [[] for i in range(4)] four_nones[0].append(100) print four_nones -->[[100], [], [], []]
所謂陷阱,天然是容易犯錯的部分,這裏簡單梳理兩例。
有些時候咱們但願定義一個可供調用的函數,其中包含一個可變參數以適應不一樣調用場景。如:
# wrong case: def append_to(ele, to=[]): to.append(ele) return to my_list_1 = append_to(10) print my_list_1 -->[10] my_list_2 = append_to(20) print my_list_2 -->[10, 20]
細心的同窗可能發現了,咱們本但願兩次函數調用分別獲得[10]與[20],結果第二次執行時卻保留了第一次執行的結果,也就是說,雖然咱們使用了可變參數做爲默認參數,致使其並未在後續調用時刷新。Python在函數定義而非調用時自動計算其默認參數。
一個解決的簡單方法是,直接設置一個默認值表示沒有提供默認參數,而是每次從新初始化對象:
def append_to(ele, to=None): if to is None: to=[] to.append(ele) return to my_list_1 = append_to(10) print my_list_1 -->[10] my_list_2 = append_to(20) print my_list_2 -->[20]
有些時候,咱們但願能夠採用循環的方式建立多個惟一性函數,而這時候其中的循環變量帶來的延遲綁定可能致使錯誤。如:
# wrong case: def create_multipliers(): return [lambda x : x * i for i in range(5)] for multiplier in create_multipliers(): print multiplier(2) -->8 -->8 -->8 -->8 -->8
本來但願的結果是[0,2,4,6,8],結果卻徹底同樣。其緣由在於for循環依次訪問函數對象列表時,確定函數對象生成函數已經完成,返回的函數對象中i值所有爲4,所以致使結果一致。此時只須要單獨綁定一個默認參數i_0,避免受到i值影響便可:
def create_multipliers(): return [lambda x, i_0 = i : x * i_0 for i in range(5)] for multiplier in create_multipliers(): print multiplier(2) -->0 -->2 -->4 -->6 -->8
今天所梳理的部分集中在兩個方面: