Python代碼規範

code review中一些小結, 還沒來得及加例子, 簡要記錄, 供參考html

law

一: 一切都與複雜度有關
二: 代碼應當易於理解python

對人:git

"好程序員」應當不遺餘力, 把程序寫得讓其餘程序員(以及之後的本身)容易理解.程序員

對代碼:github

  1. 代碼被閱讀的次數遠多於編寫和修改的次數
  2. E = mc2 (Error = more codes)

對項目:數據庫

公式: 可行性=(當前價值+將來價值)/(實現成本+維護成本). 即相比下降實現成本, 下降維護成本更加劇要後端

基礎: 風格

團隊成員遵照統一的風格, 保持風格的一致性, 減小理解難度數據結構

遵循基礎的編碼風格:框架

請仔細閱讀, 使用對應編輯器插件工具協助檢查編輯器

  • 遵循 pep8 風格
    利用pep8工具(編輯器相關插件)來解決這個問題, 在review以前處理. 以免在review過程當中出現此類問題.

  • 遵循 Google Code Style / 中文版

  • 不要吝嗇空行, 把相關的代碼行分組, 造成代碼塊. 聲明按塊組織起來, 而且把代碼分紅」段落」(按步驟/順序/邏輯結構分), 排版合理

  • 每行只寫一個語句, 每行只聲明一個變量

註釋

註釋應該有很高的價值(傳遞信息/空間佔用)

  • 代碼自己應該盡力作到自說明
  • 註釋, 記錄了在寫代碼過程當中的思考, 保持緊湊, 簡單準確的描述
  • 不要使用尾註釋. 容易被整行拷貝/不容易被編輯修改/逐漸腐爛

    x = 1  # bad comment
    
    # good comment
    x = 1
  • 不須要的代碼, 維護到版本庫後(寫明commit info), 而後刪除. 不要註釋起來

  • 不要給很差的命名加註釋, 應該去修改命名
  • 不要給那些從代碼自己就能快速推斷出來的事實寫註釋.(不要爲了註釋而註釋)
  • 對於複雜的計算邏輯, 要給出註釋, 能夠經過列舉例子, 簡單的輸入輸出來描述
  • 對於大段的邏輯或模塊, 須要給總結性註釋
  • 註釋代碼時, 應注重-爲什麼作, 而不是-怎麼作
  • 每行註釋前用一個空行分開. 註釋縮進要和相應代碼一致

命名

把信息裝入名字中.(自說明)

  • 儘可能短, 可是要包含足夠的信息(刨掉其中毫無心義的詞)
  • 命名必定要有意義, 儘可能少使用單個字符做爲命名, 除非短表達式(列表解析/lambda等)以及小的做用域範圍
  • 常量大寫, 變量小寫, 類名駝峯, 函數名小寫加下劃線, 不要混用下劃線和駝峯.
  • 不要使用關鍵字命名, 例如typedir
  • 避免使用容易混淆的命名, 防歧義
  • 慎用首字母縮略詞和縮寫, 除非團隊成員都理解(不要妄圖用註釋來解決這個問題, 即, 不要註釋很差的命名)
  • 不要使用大小寫來區分不一樣對象
  • 同一個變量, 在多個地方, 先後端/數據庫/不一樣函數/請求等, 儘可能保持命名一致性
  • 不要懼怕過長的命名, 保證易於理解和閱讀(現代編輯器能夠搞定自動補全和批量變動的問題)
  • 使用具體的名字, 而不是泛化的名字, 例如params/args等, 沒有隱含任何信息
  • bool類型, 除非名字自己有True/False的含義, 不然建議統一使用is_前綴
  • 不要使用雙重否認的命名: is_not_pass
  • for a in b, 注意 ab 的單複數區分

常量

  • 常量大寫
  • 做用於同一個模塊/邏輯的多個常量, 建議使用統一的前綴
  • 將常量統一組織到某個文件/某幾個文件, 並寫明註釋.
  • 函數/循環中的正則, 請預先compile, 放入變量中.
  • 善用Enum, 對可讀性提高很大
  • 同一個枚舉變量中, 其包含類型應當一致

變量

  • 減小變量: 變量越多, 越難所有追蹤其動向. a.減小沒有價值的中間變量 b.減小中間結果(能夠經過提早返回來消除) c.減小控制流變量
  • 縮小變量做用域: 避免全局變量(命名空間污染). 須要作到讓你的變量對儘可能少的代碼行可見.
  • 變量定義儘可能靠近其使用的地方, 或者, 在使用時定義.
  • 不要使用import *, 會出現各類突如其來的變量名, 可能致使名字空間污染, 形成詭異問題

數據結構

  • dict, 不要使用for key in d.keys(), 直接使用for key in d

表達式

原則: 保持簡短, 易懂.(拆分超長表達式)

  • 抽取反覆出現的長表達式到變量或者函數調用
  • 使用解釋變量, 將超長表達式中的自表達式抽取城一個解釋變量.(抽取, 而後使用變量, 而不是每次都重複表達式)
  • 總結變量: 一個表達式不須要解釋, 可是裝入一個新的變量中仍然有用. 短名字替代一大塊代碼. 例如: numbers[0]['obj'].name
  • 使用摩根定理: not a and not b to not (a or b)
  • 刪除公共子表達式:若是發現某個表達式總是在你面前出現,就把它賦值給一個變量
  • 中文, 請統一使用u"中文"
  • 表達式中避免使用魔數, 使用常量/枚舉替代之

控制流: 分支

  • if/else順序: a. 先處理正邏輯而不是負邏輯. b. 先處理掉簡單的狀況, 還能保證if/else在同一個屏幕內均可見(不然到了else須要回頭查) c.先處理有趣或可疑的邏輯
  • return early, 從函數中提早返回. 使用guard clause來實現. 某些狀況返回後, 將沒必要要思考某個分支出口, 剩餘注意力集中在爲數很少的狀況. 另外一個好處是, 能有效減小代碼縮進.
  • 減小嵌套: 嵌套很深的代碼很難理解, 每一個嵌套層次會在讀者’思惟棧’上又增長了一個條件. 使用return early來減小嵌套. 而循環中的減小嵌套方式, 可使用if condition: continue/break來進行提前返回.
  • 減小嵌套: 當你對代碼進行改動的時候, 從全新的角度審視它, 把它做爲一個總體來看待.只關心局部, 不敢動舊有代碼, 很容易一層層邏輯嵌套往裏加致使深層嵌套
  • 使用is來斷定是不是None, 而不是==
  • 條件語句中參數順序: 左側變量, 右側字面值/常量
  • 默認狀況都使用if...else, 三目運算只有在最簡單的狀況下才使用
  • if condition: return 則不須要else
  • 注意if/else的多層嵌套, 在某些狀況下, 判斷條件中恆真/恆假的狀況

控制流: 循環

  • 善用enumerate而不是維護index變量( enumerate 還能夠從1開始計數)
  • 除非必要(邏輯確實如此且帶break), 不然不要使用for...else.(增長理解成本)
  • 不要使用for _ in l: _.x, 可讀性太差
  • 減小循環內的if...else...嵌套層次, 可使用if condition: continue

控制流: 異常處理

異常日誌同註釋, 應該有很高的價值(傳遞信息/空間佔用)

  • 不要把全部代碼放到try except中, 只捕獲會出異常的代碼片斷. 注意粒度, 不要放入沒必要要的代碼
  • 不要吞掉異常, 處理或拋出, 同時要打日誌(使用logging而不是print打日誌)
  • 謹慎使用except Exception捕獲全部異常.
  • 不要在finally語句中使用return進行返回, 有坑.
  • 異常的錯誤信息要有用, 即足夠明確, 對問題排查有幫助.
  • 不要使用異常控制程序的流程. 濫用異常, 異常不該該處理正常邏輯
  • 不要濫用異常, 底層被調用函數早已try...except處理了, 調用方不須要再次處理

函數

函數不要太大, 嵌套不要太深

  • 參數命名的一致性: 多個參數, 選擇一個有意義的順序, 並始終一致地使用它(可讀性更好, 更容易發現問題)
  • 不要使用可變對象做爲函數默認參數的值
  • 一次只作一件事, 注意函數大小, 注意抽象/拆分
  • 抽取不相關的子問題到獨立的函數中, 例如純工具代碼, 通用代碼, 項目專屬代碼
  • 抽取反覆出現重複的代碼到獨立函數中
  • return 值不要使用0/1來表明True/False
  • 同一個函數可能存在多個return, 返回值要保持一致(個數/類型)
  • return early, 減小閱讀代碼時的邏輯堆積, 減小貫穿函數始終用於最終判斷return的變量數量. 超過3個就變得有些難以維護了, 閱讀過程當中肯定其值有困難
  • 若是函數調用鏈中, 參數或者return的值反覆出現pack/unpack, 能夠考慮用dict封裝來進行傳遞.
  • 若是發現每次調用一個函數後, 還須要對返回值進行二次處理, 則是函數封裝得不夠致使的. 需重構函數, 將處理加進去. (防止某次調用忘了二次處理致使的bug)

  • 不要使用type進行類型檢查, 用isinstance
  • 使用新式類, 駝峯命名
  • 假設類的某個屬性, 每次取出來都須要進行處理(格式化, 轉換等, 例如日期格式), 使用property封裝這層處理, 同時處理異常狀況.

模塊

  • import順序: 標準庫/第三方庫/本項目, 之間使用空行隔開
  • 多行import, 請使用from a import (b, c, d)而不是\來進行換行
  • 不要使用from A import *
  • 當相對獨立的多個邏輯代碼混雜放在一塊兒, 或者發現constant文件超大包含了大量不一樣邏輯的產量, 能夠考慮模塊切分

抽象

  • 必定不要機械地複製粘貼代碼(會出現大量的重複代碼), 應該從全局考慮是否能夠抽象
  • 多個函數之間, 若是僅有一兩行代碼不一樣, 則能夠進行抽象提取
  • 當一段類似的代碼出現兩次以上, 須要考慮封裝(注意粒度)

設計

軟件設計三大誤區: 1.編寫沒必要要的代碼 2.代碼難以修改 3.過度追求通用

  • 思考足夠充分, 減小過分設計

其餘

  • 熟悉標準庫, 減小土製輪子的機率, 能夠少寫代碼
  • 熟悉框架/優秀第三方庫提供的接口及特性, 緣由同上
  • 項目發佈前, 移除全部print語句
  • 文件/函數是否寫明做者信息? 不, 版本記錄中有做者信息. 容易造成領地, 他人不敢修改/不敢大改, 容易形成代碼腐爛. 佔用空間且沒啥用.

參考書目

  • 編寫可讀代碼的藝術
  • 簡約之美—軟件設計之道
  • 編寫高質量代碼—改善Python程序的91個建議
相關文章
相關標籤/搜索