前言
Python之禪是影響Python程式語言設計的19條原則,也是Python編碼規範的核心理念。
- 優美勝於醜陋(Python 以編寫優美的程式碼為目標)
- 明瞭勝於晦澀(優美的程式碼應當是明瞭的,命名規範,風格相似)
- 簡潔勝於複雜(優美的程式碼應當是簡潔的,不要有複雜的內部實現)
- 複雜勝於凌亂(如果複雜不可避免,那程式碼間也不能有難懂的關係,要保持介面簡潔)
- 扁平勝於巢狀(優美的程式碼應當是扁平的,不能有太多的巢狀)
- 間隔勝於緊湊(優美的程式碼有適當的間隔,不要奢望一行程式碼解決問題)
- 可讀性很重要(優美的程式碼是可讀的)
- 即便假借特例的實用性之名,也不可違背這些規則(這些規則至高無上)
- 不要包容所有錯誤,除非你確定需要這樣做(精準地捕獲異常,不寫 except:pass 風格的程式碼)
- 當存在多種可能,不要嘗試去猜測
- 而是儘量找一種,最好是唯一一種明顯的解決方案(如果不確定,就用窮舉法)
- 雖然這並不容易,因為你不是 Python 之父(這裡的 Dutch 是指 Guido )
- 做也許好過不做,但不假思索就動手還不如不做(動手之前要細思量)
- 如果你無法向人描述你的方案,那肯定不是一個好方案;反之亦然(方案測評標準)
- 名稱空間是一種絕妙的理念,我們應當多加利用(倡導與號召)
PEP8是Python官方推出的編碼規範。本規範以PEP8 編碼規範作為出發點編寫。
編碼規範的第一原則是 提升程式碼的可讀性,如果專案是從零開始請遵守該編碼規範,如果不是,在專案和該規範出現衝突時,專案自身的規範優先。每一種規範分為強制和推薦。強制是必須遵守的規範,推薦是最佳實踐。
程式碼佈局
強制 :
- 統一使用4個空格縮排
- 單行最大長度為100
- 行數超過規定,建議用小括號()將多行內容連線起來,而不推薦使用反斜槓\進行連線。
- 不要在程式碼末尾加分號,也不要用分號將兩條命令寫在同一行
- 空行使用:
- 函式之間用兩個空行隔開
- 類之間用兩個空行隔開
- 類中方法用一個空行隔開
- 函式中不同邏輯程式碼塊之間可適當插入空行
- 空格使用:
- 在二元運算子兩邊都要有空格。二元運算包括:算術(+ - * / ** )、賦值(=,+=,-=)、比較( ==, <, >, !=, in, not in, is, is not)、邏輯運算(and or not)、位運算(& | ! ~ >> <<)
- 函式關鍵字引數=兩側不需要空格。例:
res = func(name="Tom")
- 逗號後面要加空格,但是如果後面是小括號則不用。例:
List=[1, 2, 4]
- 冒號前不加空格,冒號後要加空格。但是切片裡前後都不可加空格 。例:
Dict = {key: value}
- 不要為對齊賦值語句而使用的額外空格
推薦 :
- 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:
- 在二元運算子之前應該換行,而不是在運算子之後換行
推薦:
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)
命名
強制 :
- 普通變數使用下劃線分隔命名法,即蛇形命名法。例:
max_value
- 變數名和Python關鍵字衝突,在變數末尾追加下劃線。例:
type_
- 避免使用雙下劃線開頭並結尾的名稱,該命令方式為python保留字。例:
__ init__ 用於類初始化
- 常量用全大寫字母,用下劃線連線。例:
MAX_VALUE
- 函式名遵循蛇形命名法。例:
def get_user_info
- 類名使用駝峰命名法。例:
class ControllerService
- 類中私有屬性和方法用單下劃線開頭。該定義僅為君子約定,例項化可以訪問。例:
def _previate_fun()
- 類中不希望被繼承的變數用雙下劃線開頭。例:
__user_info
- 模組應該用簡短全小寫的名字,如果為了提升可讀性,下劃線也是可以用的。
- 包使用簡短全小寫的名字,但不建議用下劃線。
推薦 :
- 使用列舉值、常量值替換沒有意義的數字
- 永遠不要使用l(小寫的L),O(大寫的O),I(大寫的I)作為單字元變數名,這些字元無法區分
- 描述性強。在可接受的長度範圍內,變數名所指向的內容描述越精確越好。儘量不要用那些過於寬泛的詞來作變數名 。推薦:last_login_datetime 不推薦:datetime
- 儘量短。命名儘量不超過5個單詞。變數名要結合程式碼情景和上下文,可以透過函式名,類名,模組名自解釋。
def get_expired_vip_users:
pass
# 返回過期vip使用者數
# 推薦
users_count = 0
# 不推薦
expired_vip_users_count = 0
- 配型匹配
- 使用is,has, allow等開頭來命名錶示boolean型別。例:
is_vip、has_error、all_empty
- 使用_id結尾,length/count開頭結尾的單詞標示int型別。例:
user_id,host_id,max_length,users_count
函式
強制:
- 函式設計要儘量短小,100行是一個參考值
- 一個函式只做一件事,保證函式語句粒度的一致性
- 禁止使用可變型別作為函式引數預設值,有慘痛教訓 一個 Python Bug 幹倒了估值 1.6 億美元的公司
# 明令禁止
List = []
def fun(num, arr=List)
pass
推薦 :
- 要將 self 作為例項方法的的第一個引數。
- 要將 cls 作為類靜態方法的第一個引數。
- 如果函式的引數名和已有的關鍵詞衝突,參考變數名和關鍵字重複的處理方法
- 函式圈複雜度可以衡量函式邏輯,圈複雜度不應該超過10(大概10個if else)
模組匯入
強制:
- 一個import語句匯入一個模組
推薦:
import os
import sys
不推薦:
import sys, os
- 匯入總是位於檔案的頂部,在模組註釋和文件字串之後,在模組的全域性變數與常量之前
- 匯入應該按照以下順序分組,每一組匯入之間加入空行:
- 標準庫匯入
- 相關第三方庫匯入
- 本地應用/庫特定匯入
- 推薦使用絕對路徑匯入
- 禁止使用萬用字元的匯入,汙染名稱空間。例:
from module import *
推薦 :
- 如果匯入的模組名較長,使用 as 給模組重新命名。例:
from moudle import module_fun as mf
註釋
強制:
- 程式碼塊註釋使用 #, 介面註釋使用 """
- 塊註釋應該至少離開程式碼2個空格,#後面跟一個空格
- 公共函式,重要的函式必須寫介面註釋
- 邏輯複雜,難以理解,指令碼程式碼等情況必須要有註釋
- 程式碼修改要同步更新註釋
推薦:
- 待實現的功能用 TODO 註釋
- 不要用註釋描述程式碼,而是說清楚功能或邏輯
真值判斷
推薦:
- 對於容器型別來說,判斷空值不要用長度等於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
- 布林型別的判斷,推薦使用 if value
greeting = True
推薦: if greeting:
不推薦: if greeting is True:
不推薦: if greeting == True:
- 對空值None的判斷優先使用None為False屬性,需要顯示判斷邏輯更加清晰時可以使用 is 關鍵字。例:
if value is None
。 - 空值判斷使用 if value is not None 而不是 if not value is None
錯誤捕獲
強制 :
- 對於無法預知錯誤型別,使用異常捕獲來保證流程正常。如網路請求
- 異常捕獲的顆粒度是行,對大段程式碼進行 try-catch,這是不負責任的表現
- 異常捕獲時分清穩定程式碼和非穩定程式碼,穩定程式碼指的是無論如何不會出錯的程式碼。
- 異常不要用來做流程控制,條件控制
- 捕獲異常是為了處理它,不要捕獲了卻什麼都不處理而拋棄之。禁止在捕獲錯誤之後使用pass不處理。如果不想處理它或不能處理,請將該異常拋給它的呼叫者。
- 禁止在 finally 塊中使用 return,finally 是最後執行的程式碼,return會覆蓋正常流程的return
推薦 :
- 存在if else 巢狀複雜的邏輯時,使用try except最佳化
- 可以透過預先檢查進行規避時,推薦不要異常捕獲來處理
- 錯誤的返回推薦異常類而不是變數
工程結構
推薦 :
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: 存放單元測試檔案