【譯】Best_Practice_For_Python最佳實踐指南

1. 合理組織你的代碼庫,選擇合適的代碼管理工具

一個普通的python項目代碼庫的結構大致包含:

project
   project/
     __init__.py
     __main__.py
     core/
     utils/
     constants/
   tests/
   docs/
   examples/
   README.md
   LISCENSE
   requirements.txt
   setup.py
   .gitignore
   .pylintrc
   .flake8

2. 遵循公共的編碼風格(code style)

PEP8 – Python社區聖經,正因爲如此,Python社區幾乎所有的代碼看起來都是一樣的風格。

  • 文件編碼和unicode

    1. 源碼文件使用UTF-8無BOM編碼格式
    2. 使用UNIX \n風格換行符,而不使用dos的\r\n
    3. py文件頭包含:#!/usr/bin/env python # -*- coding: utf-8 -*-
  • 命名

    1. 小寫:函數,方法,變量,包,模塊
    2. 駝峯:類名
    3. 單下劃線開頭:受保護方法和內部函數
    4. 雙下劃線開頭:私有方法
    5. 全大寫:常量
  • 模塊導入:

    1. 導入整個模塊,而不是模塊裏的符號(類,函數等),除非第三包有明確說明要導入符號。

    ​ 理由:這樣可以有效避免循環導入。

    *個人理解這裏有問題,如果py中有額外的函數調用,數據修改動作,import *會隱含被執行,且問題難以發現

    1. 在文件開頭導入模塊,按系統模塊,第三方模塊,本地模型的屬性導入。

​ 理由:可以清晰的瞭解模塊的來源。IDE有優化導入的快捷鍵ctrl+thift+o

  • 縮進:

    4個空格,不用Tab

  • 熟悉常見的約定

    要了解__init__.py, __main__.py的作用 瞭解if __name__ == "__main__": 的作用 瞭解package加載的流程: sys.path, sys.modules的作用

  • 註釋

    參考PEP257,使用reStructuredText和Sphinx可以生成項目文檔

  • 單行代碼不要過長,使用括號進行換行 或 \ 換行

  • 合理的使用空行,讓代碼更可讀

  • 代碼儘量扁平,不要嵌套太深

    1. if、for、 while, try/except/finally、with不要嵌套太多
    2. 方法定義和調用時,參數過多,不合理的換行也會導致代碼結構不好看

​ [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Vxzy1JQX-1593745654598)(file:///C:\Users\W00448~1\AppData\Local\Temp\msohtmlclip1\01\clip_image002.png)]

  • 儘量多寫單元測試:
    1. 單元要小,測試要快(當然慢也比沒有好),通常一個類一個TestCase
    2. 有了單元測試以後,重構起來,比較放心
    3. 集成測試:按用例和場景來

3. 立即修復破損的窗戶(broken window)

破損的窗戶的理論同樣適用於編碼,當你發現代碼有任何問題(不管是壞的設計,錯誤的決策,還是糟糕的代碼),都請立即修復它。

4. 重構你的代碼

邊開發邊重構。寫代碼時,如果發現有些不妥的地方,要及時重構和修改、測試。

有時會想,先做完再重構,忘掉這種想法。這種想法不可取。越往後拖,越不易重構,越懶得重構。

重構是一個長期持續的活動。

字符串拼接,大量的拼接使用+,性能不高

# py  
s = "".join(["Life", "is", "short", "I", "love", "Python"]) # better  
s = "Life" + "is" + "short" + "I" + "love" + "Python" # worse

in的使用

 # 儘可能的使用in,使用__contains__支持in,加上使用__iter__,可以支持for x in y
for key in d: print(key) # better
for key in d.keys(): print(key) # worse, 不過在遍歷的同時需修改字典,可以這樣

if key not in d: d[key] = 1 # better
if not key in d: d[key] = 1 # worse

if的使用

if not x: 要好過於:if x == 0, if x == "", if x is None, if x == False  
if x: 要好過於 if x != 0, if x is not None, if x != None  
或者用if len(x) ?= 0 來判斷
if 1 < x < 5 要好過於 if x > 1 and x < 5  # Python運算符支持級聯

if x is Noneif x is not None 要好過於 if x == Noneif x != None  
if x == 1 要好過於 if (x == 1) # 後面的括號是多餘的  

交換變量的值,不要使用臨時變量

a, b = b, a a, b, c, d = d, b, c, a

代碼性能優化

  1. 優化前要進行性能分析,避免盲目的優化,影響了代碼的可讀性。
    
  2. 儘量使用時間複雜度小的算法,一般來說,數據量大的時候,好的算法優勢越明顯。

  3. 使用能夠正常工作的最簡單的方式,比如使用.startsWith就比使用正則匹配好

  4. **使用dict或者set來進行元素查找,而不是使用list**
    
  5. 使用map/filter來對list中的元素進行處理,而不使用for循環

  6. 使用列表推導而不是使用for循環, 但是推導裏面邏輯複雜,使用for的可讀性高

  7. 儘量減少遍歷的趟數,一趟遍歷能夠處理完,不要遍歷多趟。

​ [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-c0jjgdWH-1593745654602)(file:///C:\Users\W00448~1\AppData\Local\Temp\msohtmlclip1\01\clip_image004.png)]

  1. 需要從redis中拿多個值的時候,可以使用管道,減少IO交互次數。

  2. 使用多線程或者協程來處理IO密集型任務。
    

可複用的面向對象設計

  1. 合理使用組合,繼承,混入來進行代碼複用

​ 優先使用組合(Has A),其次使用繼承(必須是Is A)。使用混入(Mixin)來實現多重繼承,能夠讓代碼看起來比較清晰。

​ 搜索平臺中三種方式都使用了,比如數據庫模型IspTable。算法模型ModelMixin,分詞器JiebaTokenizer。

  1. 合理構建可以複用的工具包,工具類

​ DBHelper,LogHelper,app.common.utils

  1. 使用monkey-patch或者繼承的方式來擴展第三方包的功能。
    

​ 如:jieba_wrap中的實現方式

​ [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-uUyFM0o6-1593745654603)(file:///C:\Users\W00448~1\AppData\Local\Temp\msohtmlclip1\01\clip_image006.png)]

多線程,多進程

  1. 不要在計算密集型任務中使用多線程,沒有意義。在IO密集型任務中使用多線程可以提升處理速度。

  2. 多進程併發寫日誌到同一個文件中,自帶的日誌包會有問題,使用concurrent_log_handler
    

設計模式

合理的使用設計模式,能簡化相應的編程任務,是代碼清晰可讀。

  1. 裝飾器模式: 日誌,異常,性能等

  2. 單例模式:Jieba分詞器,按租戶粒度隔離
    
  3. 發佈訂閱模式,邏輯解耦
    

常用類的命名約定

  1. 前綴: SimpleXXX、DefaultXXX, StandardXXX

  2. 後綴: XXXService, XXXMixin,XXXHelper, XXXError, XXXException,XXXEnum

  3. 接口:在聲明是多使用XXXable,表示實現類具有該能力,如Runable,Configurable,Customizable,Imutable,Iterable, Cloneable, Serializable...
    
  4. 實現類:的聲明多使用XXXRunner, XXXConfiguration等名詞結構。
    

5. 創建一致的文檔

看起來是個負擔,但是合適的文檔是項目生命週期中產生整潔代碼的基石。Python社區適用下面三個簡單的工具或者概念來簡化了文檔的編寫:

  • reStructredText

  • Docstrings

  • Sphinx

通過這三個工具,你可以在Python代碼中,編寫符合reStructredText語法的註釋(Docstrings),然後通過Sphinx這個工具自動生產項目的各種格式的文檔(PDF,HTML…)。並且可以把你項目的文檔發佈到ReadTheDocs文檔庫中,供別人在線查看。

大量的開源項目都是這種方式維護文檔的:

  • flask

  • gunicorn

  • torando

6. 熟練使用PyPI

從PyPI中獲取別人的項目,發佈你的項目到PyPI中。

pip install requests

7. 參考書籍

• The Python Cookbook

• Fluent Python

• Effective Python: 59 Specific Ways to Write Better Python

8. Python之禪

The Zen of Python, by Tim Peters 

 Beautiful is better than ugly.
 代碼美麗勝於醜陋。

 Explicit is better than implicit.
 顯示勝於隱式。

 Simple is better than complex.
 簡單勝於複雜。

 Complex is better than complicated.
 複雜勝於錯綜複雜。

 Flat is better than nested.
 扁平勝於嵌套。

 Sparse is better than dense.
 稀疏勝於密集。

 Readability counts.
 可讀性非常重要。

 Special cases aren't special enough to break the rules.
 Although practicality beats purity.
 個例不足以特殊到可以打破規則,雖然實用性勝過純粹性。

 Errors should never pass silently.
 Unless explicitly silenced.
 異常不應該被忽略,除非你顯式地這麼做。

 In the face of ambiguity, refuse the temptation to guess.
 模棱兩可的時候,不要猜測。

 There should be one-- and preferably only one --obvious way to do it.
 Although that way may not be obvious at first unless you're Dutch.
 應該有一種(最好只有一種)顯而易見的方式來做。雖然剛開始那種方式不那麼明顯。

 Now is better than never.
 Although never is often better than *right* now.
 現在好過於永遠不。雖然永遠不經常好過於立即。


 If the implementation is hard to explain, it's a bad idea.
 If the implementation is easy to explain, it may be a good idea.
 一個實現方式很容易解釋,那就是好主意,否則是壞主意。

 Namespaces are one honking great idea 
 命名空間是個很棒的主意。

 -- let's do more of those!

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