python編碼規範

R-B發表於2021-09-09


遵循良好的編碼風格,可以有效的提高程式碼的可讀性,降低出錯機率和維護難度。在團隊開發中,使用(儘量)統一的編碼風格,還可以降低溝通成本。

網上有很多版本的編碼規範,基本上都是遵循 PEP8 的規範:

  • PEP 0008 – Style Guide for Python Code

  • Google 的 Python 風格指南

  • Python Guide - Code Style

  • Pocoo Styleguide

除了在編碼時主動遵循規範,還有很多有用的工具:

  • IntelliJ IDEA 和 PyCharm 的格式化程式碼功能

  • Google 開源的 Python 檔案格式化工具:github.com/google/yapf

  • pyflakes, pylint 等工具及各種編輯器的外掛

本文的內容主要摘自網際網路上各種版本的規範,因為公司有些小夥伴程式碼風格不太好,所以整理了一份算是團隊的編碼規範。


縮排

  • 不要使用 tab 縮排

  • 使用任何編輯器寫 Python,請把一個 tab 展開為 4 個空格

  • 絕對不要混用 tab 和空格,否則容易出現 IndentationError

空格

  • 在 list, dict, tuple, set, 引數列表的 , 後面加一個空格

  • 在 dict 的 : 後面加一個空格

  • 在註釋符號 # 後面加一個空格,但是 #!/usr/bin/python 的 # 後不能有空格

  • 運算子兩端加一個空格,如 +-*/|&=

  • 接上一條,在引數列表裡的 = 兩端不需要空格

  • 括號((){}[])內的兩端不需要空格

空行

  • function 和 class 頂上兩個空行

  • class 的 method 之間一個空行

  • 函式內邏輯無關的段落之間空一行,不要過度使用空行

  • 不要把多個語句寫在一行,然後用 ; 隔開

  • if/for/while 語句中,即使執行語句只有一句,也要另起一行

換行

  • 每一行程式碼控制在 80 字元以內

  • 使用  或 () 控制換行,舉例:

    def foo(first, second, third, fourth, fifth,        sixth, and_some_other_very_long_param):    user = User.objects.filter_by(first=first, second=second, third=third)         .skip(100).limit(100)         .all()text = ('Long strings can be made up '        'of several shorter strings.')

命名

  • 使用有意義的,英文單詞或片語,絕對不要使用漢語拼音

  • package/module 名中不要出現 -

  • 各種型別的命名規範:

    Type Public Internal
    Modules lower_with_under _lower_with_under
    Packages lower_with_under
    Classes CapWords _CapWords
    Exceptions CapWords
    Functions lower_with_under() _lower_with_under()
    Global/Class Constants CAPS_WITH_UNDER _CAPS_WITH_UNDER
    Global/Class Variables lower_with_under _lower_with_under
    Instance Variables lower_with_under _lower_with_under (protected) or __lower_with_under (private)
    Method Names lower_with_under() _lower_with_under() (protected) or __lower_with_under() (private)
    Function/Method Parameters lower_with_under
    Local Variables lower_with_under

import

  • 所有 import 儘量放在檔案開頭,在 docstring 下面,其他變數定義的上面

  • 不要使用 from foo imort *

  • import 需要分組,每組之間一個空行,每個分組內的順序儘量採用字典序,分組順序是:

  1. 標準庫

  2. 第三方庫

  3. 本專案的 package 和 module

  • 不要使用隱式的相對匯入(implicit relative imports),可是使用顯示的相對匯入(explicit relative imports),如 from ..utils import validator,最好使用全路徑匯入(absolute imports)

  • 對於不同的 package,一個 import 單獨一行,同一個 package/module 下的內容可以寫一起:

    # badimport sys, os, time# goodimport osimport sysimport time# okfrom flask import Flask, render_template, jsonify
  • 為了避免可能出現的命名衝突,可以使用 as 或匯入上一級名稱空間

  • 不要出現迴圈匯入(cyclic import)

  • 註釋

    • 文件字串 docstring, 是 package, module, class, method, function 級別的註釋,可以透過 __doc__ 成員訪問到,註釋內容在一對 """ 符號之間

    • function, method 的文件字串應當描述其功能、輸入引數、返回值,如果有複雜的演算法和實現,也需要寫清楚

    • 不要寫錯誤的註釋,不要無謂的註釋

      # bad 無謂的註釋x = x + 1       # increase x by 1# bad 錯誤的註釋x = x - 1       # increase x by 1
    • 優先使用英文寫註釋,英文不好全部寫中文,否則更加看不懂

    異常

    • 不要輕易使用 try/except

    • except 後面需要指定捕捉的異常,裸露的 except 會捕捉所有異常,意味著會隱藏潛在的問題

    • 可以有多個 except 語句,捕捉多種異常,分別做異常處理

    • 使用 finally 子句來處理一些收尾操作

    • try/except 裡的內容不要太多,只在可能丟擲異常的地方使用,如:

      # badtry:    user = User()    user.name = "leon"    user.age = int(age) # 可能丟擲異常    user.created_at = datetime.datetime.utcnow()    db.session.add(user)    db.session.commit() # 可能丟擲異常except:    db.session.rollback()# bettertry:    age = int(age)except (TypeError, ValueError):    return # 或別的操作user = User()user.name = "leon"user.age = ageuser.created_at = datetime.datetime.utcnow()db.session.add(user)try:    db.session.commit()except sqlalchemy.exc.SQLAlchemyError: # 或者更具體的異常    db.session.rollback()finally:    db.session.close()
    • 從 Exception 而不是 BaseException 繼承自定義的異常類

    Class(類)

    • 顯示的寫明父類,如果不是繼承自別的類,就繼承自 object 類

    • 使用 super 呼叫父類的方法

    • 支援多繼承,即同時有多個父類,建議使用 Mixin

    編碼建議

    字串

    • 使用字串的 join 方法拼接字串

    • 使用字串型別的方法,而不是 string 模組的方法

    • 使用 startswith 和 endswith 方法比較字首和字尾

    • 使用 format 方法格式化字串

    比較

    • 空的 liststrtuplesetdict 和 00.0None 都是 False

    • 使用 if some_list 而不是 if len(some_list) 判斷某個 list 是否為空,其他型別同理

    • 使用 is 和 is not 與單例(如 None)進行比較,而不是用 == 和 !=

    • 使用 if a is not None 而不是 if not a is None

    • 用 isinstance 而不是 type 判斷型別

    • 不要用 == 和 != 與 True 和 False 比較(除非有特殊情況,如在 sqlalchemy 中可能用到)

    • 使用 in 操作:

    1. 用 key in dict 而不是 dict.has_key()

      # badif d.has_key(k):    do_something()# goodif k in d:    do_something()
    2. 用 set 加速 “存在性” 檢查,list 的查詢是線性的,複雜度 O(n),set 底層是 hash table, 複雜度 O(1),但用 set 需要比 list 更多記憶體空間

    其他

    • 使用列表表示式(list comprehension),字典表示式(dict comprehension, Python 2.7+) 和生成器(generator)

    • dict 的 get 方法可以指定預設值,但有些時候應該用 [] 操作,使得可以丟擲 KeyError

    • 使用 for item in list 迭代 listfor index, item in enumerate(list) 迭代 list 並獲取下標

    • 使用內建函式 sorted 和 list.sort 進行排序

    • 適量使用 mapreducefilter 和 lambda,使用內建的 allany 處理多個條件的判斷

    • 使用 defaultdict (Python 2.5+), Counter(Python 2.7+) 等 “冷門” 但好用的標準庫演算法和資料結構

    • 使用裝飾器(decorator)

    • 使用 with 語句處理上下文

    • 有些時候不要對型別做太過嚴格的限制,利用 Python 的鴨子型別(Duck Type)特性

    • 使用 logging 記錄日誌,配置好格式和級別

    • 瞭解 Python 的 Magic Method:A Guide to Python’s Magic Methods, Python 魔術方法指南

    • 閱讀優秀的開原始碼,如 Flask 框架, Requests for Humans

    • 不要重複造輪子,檢視標準庫、PyPi、Github、Google 等使用現有的優秀的解決方案

      本人影片網站:無任何廣告 大家沒事了 可以去踩一下 看看電影和連續劇也有各大衛視直播 還可以下載app版 有多種小工具


    來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4560/viewspace-2803580/,如需轉載,請註明出處,否則將追究法律責任。

    相關文章