Python編程規範+最佳實踐

image

前言

Python之禪是影響Python編程語言設計的19條原則,也是Python編碼規範的核心理念。

  • 優美勝於醜陋(Python 以編寫優美的代碼爲目標)
  • 明瞭勝於晦澀(優美的代碼應當是明瞭的,命名規範,風格相似)
  • 簡潔勝於複雜(優美的代碼應當是簡潔的,不要有複雜的內部實現)
  • 複雜勝於凌亂(如果複雜不可避免,那代碼間也不能有難懂的關係,要保持接口簡潔)
  • 扁平勝於嵌套(優美的代碼應當是扁平的,不能有太多的嵌套)
  • 間隔勝於緊湊(優美的代碼有適當的間隔,不要奢望一行代碼解決問題)
  • 可讀性很重要(優美的代碼是可讀的)
  • 即便假借特例的實用性之名,也不可違背這些規則(這些規則至高無上)
  • 不要包容所有錯誤,除非你確定需要這樣做(精準地捕獲異常,不寫 except:pass 風格的代碼)
  • 當存在多種可能,不要嘗試去猜測
  • 而是儘量找一種,最好是唯一一種明顯的解決方案(如果不確定,就用窮舉法)
  • 雖然這並不容易,因爲你不是 Python 之父(這裏的 Dutch 是指 Guido )
  • 做也許好過不做,但不假思索就動手還不如不做(動手之前要細思量)
  • 如果你無法向人描述你的方案,那肯定不是一個好方案;反之亦然(方案測評標準)
  • 命名空間是一種絕妙的理念,我們應當多加利用(倡導與號召)

PEP8是Python官方推出的編碼規範。本規範以PEP8 編碼規範作爲出發點編寫。
編碼規範的第一原則是 提升代碼的可讀性,如果項目是從零開始請遵守該編碼規範,如果不是,在項目和該規範出現衝突時,項目自身的規範優先。每一種規範分爲強制和推薦。強制是必須遵守的規範,推薦是最佳實踐。

代碼佈局

強制 :

  1. 統一使用4個空格縮進
  2. 單行最大長度爲100
  3. 行數超過規定,建議用小括號()將多行內容連接起來,而不推薦使用反斜槓\進行連接。
  4. 不要在代碼末尾加分號,也不要用分號將兩條命令寫在同一行
  5. 空行使用:
    1. 函數之間用兩個空行隔開
    2. 類之間用兩個空行隔開
    3. 類中方法用一個空行隔開
    4. 函數中不同邏輯代碼塊之間可適當插入空行
  6. 空格使用:
    1. 在二元運算符兩邊都要有空格。二元運算包括:算術(+ - * / ** )、賦值(=,+=,-=)、比較( ==, <, >, !=, in, not in, is, is not)、邏輯運算(and or not)、位運算(& | ! ~ >> <<)
    2. 函數關鍵字參數=兩側不需要空格。例: res = func(name="Tom")
    3. 逗號後面要加空格,但是如果後面是小括號則不用。例:List=[1, 2, 4]
    4. 冒號前不加空格,冒號後要加空格。但是切片裏前後都不可加空格 。例:Dict = {key: value}
    5. 不要爲對齊賦值語句而使用的額外空格

推薦 :

  1. import或函數存在續行的情況,遵守掛行縮進對齊
  • 第一行不應該有參數
  • 使用縮進以區分自己是續行

推薦:

def ats_import_dataset(
    db: Session = Depends(deps.get_db),
    ats_import: schemas.AtsDataSetImport,
    current_user: models.User = Depends(deps.get_current_active_user),
    controller_client: ControllerClient = Depends(deps.get_controller_client),
    background_tasks: BackgroundTasks,
 ) -> Dict:
  1. 在二元運算符之前應該換行,而不是在運算符之後換行

推薦:

income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)

不推薦:

income = (gross_wages +
          taxable_interest +
          (dividends - qualified_dividends) -
          ira_deduction - 
          student_loan_interest)

命名

強制 :

  1. 普通變量使用下劃線分隔命名法,即蛇形命名法。例: max_value
  2. 變量名和Python關鍵字衝突,在變量末尾追加下劃線。例: type_
  3. 避免使用雙下劃線開頭並結尾的名稱,該命令方式爲python保留字。例:__ init__ 用於類初始化
  4. 常量用全大寫字母,用下劃線連接。例:MAX_VALUE
  5. 函數名遵循蛇形命名法。例:def get_user_info
  6. 類名使用駝峯命名法。例:class ControllerService
  7. 類中私有屬性和方法用單下劃線開頭。該定義僅爲君子約定,實例化可以訪問。例:def _previate_fun()
  8. 類中不希望被繼承的變量用雙下劃線開頭。例:__user_info
  9. 模塊應該用簡短全小寫的名字,如果爲了提升可讀性,下劃線也是可以用的。
  10. 包使用簡短全小寫的名字,但不建議用下劃線。

推薦 :

  1. 使用枚舉值、常量值替換沒有意義的數字
  2. 永遠不要使用l(小寫的L),O(大寫的O),I(大寫的I)作爲單字符變量名,這些字符無法區分
  3. 描述性強。在可接受的長度範圍內,變量名所指向的內容描述越精確越好。儘量不要用那些過於寬泛的詞來作變量名 。推薦:last_login_datetime 不推薦:datetime
  4. 儘量短。命名儘量不超過5個單詞。變量名要結合代碼情景和上下文,可以通過函數名,類名,模塊名自解釋。
def get_expired_vip_users:
    pass

    # 返回過期vip用戶數
    
    # 推薦
    users_count = 0 
    
    # 不推薦
    expired_vip_users_count = 0
  1. 配型匹配
  • 使用is,has, allow等開頭來命名錶示boolean類型。例:is_vip、has_error、all_empty
  • 使用_id結尾,length/count開頭結尾的單詞標示int類型。例:user_id,host_id,max_length,users_count

函數

強制:

  1. 函數設計要儘量短小,100行是一個參考值
  2. 一個函數只做一件事,保證函數語句粒度的一致性
  3. 禁止使用可變類型作爲函數參數默認值,有慘痛教訓 一個 Python Bug 幹倒了估值 1.6 億美元的公司
# 明令禁止
 List = []
 def fun(num, arr=List)
    pass

推薦 :

  1. 要將 self 作爲實例方法的的第一個參數。
  2. 要將 cls 作爲類靜態方法的第一個參數。
  3. 如果函數的參數名和已有的關鍵詞衝突,參考變量名和關鍵字重複的處理方法
  4. 函數圈複雜度可以衡量函數邏輯,圈複雜度不應該超過10(大概10個if else)

模塊導入

強制:

  1. 一個import語句導入一個模塊

推薦:

import os
import sys

不推薦:

import sys, os
  1. 導入總是位於文件的頂部,在模塊註釋和文檔字符串之後,在模塊的全局變量與常量之前
  2. 導入應該按照以下順序分組,每一組導入之間加入空行:
  • 標準庫導入
  • 相關第三方庫導入
  • 本地應用/庫特定導入
  1. 推薦使用絕對路徑導入
  2. 禁止使用通配符的導入,污染命名空間。例: from module import *

推薦 :

  1. 如果導入的模塊名較長,使用 as 給模塊重命名。例:from moudle import module_fun as mf

註釋

強制:

  1. 代碼塊註釋使用 #, 接口註釋使用 """
  2. 塊註釋應該至少離開代碼2個空格,#後面跟一個空格
  3. 公共函數,重要的函數必須寫接口註釋
  4. 邏輯複雜,難以理解,腳本代碼等情況必須要有註釋
  5. 代碼修改要同步更新註釋

推薦:

  1. 待實現的功能用 TODO 註釋
  2. 不要用註釋描述代碼,而是說清楚功能或邏輯

真值判斷

推薦:

  1. 對於容器類型來說,判斷空值不要用長度等於0,可以使用空序列布爾值爲False這個屬性來判斷。

python 中 0、None、空字符串、空列表、空元組、空字典、空集合、空集合,都可以視爲False,if 判斷可以視爲False。其他情況都爲True。
推薦:

user_list = []
if not user_list:
    pass 

if user_list:
    pass

不推薦:

user_list = [] 
if len(user_list):
    pass 
if not len(user_list): 
    pass
  1. 布爾類型的判斷,推薦使用 if value
greeting = True
推薦: if greeting:
不推薦: if greeting is True:
不推薦: if greeting == True:
  1. 對空值None的判斷優先使用None爲False屬性,需要顯示判斷邏輯更加清晰時可以使用 is 關鍵字。例:if value is None
  2. 空值判斷使用 if value is not None 而不是 if not value is None

錯誤捕獲

強制 :

  1. 對於無法預知錯誤類型,使用異常捕獲來保證流程正常。如網絡請求
  2. 異常捕獲的顆粒度是行,對大段代碼進行 try-catch,這是不負責任的表現
  3. 異常捕獲時分清穩定代碼和非穩定代碼,穩定代碼指的是無論如何不會出錯的代碼。
  4. 異常不要用來做流程控制,條件控制
  5. 捕獲異常是爲了處理它,不要捕獲了卻什麼都不處理而拋棄之。禁止在捕獲錯誤之後使用pass不處理。如果不想處理它或不能處理,請將該異常拋給它的調用者。
  6. 禁止在 finally 塊中使用 return,finally 是最後執行的代碼,return會覆蓋正常流程的return

推薦 :

  1. 存在if else 嵌套複雜的邏輯時,使用try except優化
  2. 可以通過預先檢查進行規避時,推薦不要異常捕獲來處理
  3. 錯誤的返回推薦異常類而不是變量

工程結構

推薦 :
Python項目沒有其他語言如Java的Maven來構造固定的工程文件目錄,結合Python社區推薦的工程目錄制定推薦結構如下:

sample_project
 ├── readme.md
 ├── docs
 │   ├── api.yml
 │   └── public_read.md
 ├── requirements.txt
 ├── app
 │   ├── __init__.py
 │   ├── core.py
 │   └── helpers.py
 ├── config
 │   ├── mysql.py
 ├── deploy
 │   ├── __init__.py
 │   └── run.sh
 ├── db
 │ 
 ├── utils
 │ 
 └── tests
     ├── __init__.py
     └── test_basic.py

readme.md: 項目說明文件
docs: 存放項目文檔,包括功能詳細說明,api docs等
requirements.txt: 存放軟件依賴的外部Python包列表
app: 存放項目接口主要代碼的目錄
config: 存放項目配置文件,如mysql,redis等配置項
deploy:存放部署文件,部署腳本等。如docker-compse.yml文件
db: 存放數據庫相關代碼
utils: 存放項目工具代碼,通常和業務無關
tests: 存放單元測試文件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章