Python開發(fā)指南:最佳實踐精選
總體原則
價值
-
“為別人開發(fā)你也想要使用的工具。” ——Kenneth Reitz
-
"簡潔總是勝過可用。" ——Pieter Hintjens
-
"滿足90%的使用場景。忽略那些說不的人。" ——Kenneth Reitz
-
"優(yōu)美勝過丑陋。" ——PEP 20
-
為開源(甚至是閉源項目)而開發(fā)。
一般開發(fā)準則
-
“明確勝過含蓄。” —— PEP 20
-
“易讀亦有價。” —— PEP 20
-
“人人都能打補丁。” —— 可汗學院開發(fā)文檔
-
一旦發(fā)現破窗(設計錯誤,決策失誤或編碼質量低),馬上修補。
-
“現在做也要勝過不去做。” —— PEP 20
-
"測試要徹底。撰寫新功能文檔。"
-
人力驅動型開發(fā),比測試驅動型開發(fā)更重要。(譯者:原文為Even more important that Test-Driven Development--Human-Driven Development,譯者認為more important that應該是more important than,應該是作者筆誤,否則意思不通,)
-
這些準則可能——應該是很可能——會改變。
特殊準則
風格
感覺合理的話,就遵循PEP 8。
命名
-
變量、函數、方法、包、模塊
-
小寫,并使用下劃線分隔單詞(lower_case_with_underscores)
-
類、異常
-
首字母大寫(CapWords)
-
受保護的方法和內部函數
-
單下劃線開頭(_single_leading_underscore(self, ...))
-
私有的方法
-
雙下劃線開頭(__double_leading_underscore(self, ...))
-
常量
-
字母全部大寫,單詞間用下劃線分隔(ALL_CAPS_WITH_UNDERSCORES)
一般命名準則
盡量不要使用只有一個字母的變量名(例如,l,I,O等)。
例外:在很簡短的代碼塊中,如果變量名的意思可以從上下文明顯地看出來,即可。
沒問題
for e in elements:
e.mutate()
避免重復變量名。
正確的做法
import audio
core = audio.Core()
controller = audio.Controller()
錯誤的做法
import audio
core = audio.AudioCore()
controller = audio.AudioController()
“反向標記”更好。
正確的做法
elements = ...
elements_active = ...
elements_defunct = ...
錯誤的做法
elements = ...
active_elements = ...
defunct_elements ...
避免使用getter和setter方法。
正確的做法
person.age = 42
錯誤的做法
person.set_age(42)
縮進
用4個空格符——永遠別用Tab制表符。就說這么多。
模塊引用
引用整個模塊,而不是模塊中的單個標識符。舉個例子,假設一個cantee模塊下面,有一個sessions.py文件,
正確的做法
import canteen
import canteen.sessions
from canteen import sessions
錯誤的做法
from canteen import get_user # Symbol from canteen/__init__.py
from canteen.sessions import get_session # Symbol from canteen/sessions.py
例外:如果第三方代碼的文檔中明確說明要單個引用,即可。
理由:避免循環(huán)引用。看這里。
把代碼引用部分放在文件的頂部,按下面的順序分成三個部分,每個部分之間空一行。 1. 系統(tǒng)引用 2. 第三方引用 3. 本地引用
理由:明確顯示每個模塊的引用來源。
文檔
遵循PEP 257提出的文檔字符串準則。reStructuredText (reST) 和Sphinx有助于確保文檔符合標準。
對于功能明顯的函數,撰寫一行文檔字符串。
"""返回``foo``的路徑名."""
多行文檔字符串應包括:
-
一行摘要
-
合適的話,請描述使用場景
-
參數
-
返回數據類型和語義信息,除非返回
None
"""訓練一個用來區(qū)分Foo和Bar的模型。
用法::
>>> import klassify
>>> data = [("green", "foo"), ("orange", "bar")] >>> classifier = klassify.train(data):param train_data:
(color, label)
形式的一個元祖列表。:rtype: A :class:
Classifier <Classifier>
"""
注意
使用主動詞(“返回”),而不是描述性的單詞(“返回值”)。 在類的文檔字符串中為__init__
方法撰寫文檔。
class Person(object):
"""A simple representation of a human being. :param name: A string, the person's name. :param age: An int, the person's age. """ def __init__(self, name, age): self.name = name self.age = age
關于注釋
盡量少用。與其寫很多注釋,不如提高代碼可讀性。通常情況下,短小的方法比注釋更有效。
錯誤的做法
# If the sign is a stop sign
if sign.color == 'red' and sign.sides == 8:
stop()
正確的做法
def is_stop_sign(sign):
return sign.color == 'red' and sign.sides == 8
if is_stop_sign(sign):
stop()
但是的確要寫注釋時,請牢記:“遵循斯托克與懷特所寫的《風格的要素》。” —— PEP 8
每行的長度
不要過分在意。80到100個字符都是沒問題的。
使用括號延續(xù)當前行。
wiki = (
"The Colt Python is a .357 Magnum caliber revolver formerly manufactured "
"by Colt's Manufacturing Company of Hartford, Connecticut. It is sometimes "
'referred to as a "Combat Magnum". It was first introduced in 1955, the '
"same year as Smith & Wesson's M29 .44 Magnum."
)
測試
盡量爭取測試全部代碼,但也不必執(zhí)著于覆蓋率。
一般測試準則
-
使用較長的、描述性的名稱。通常情況下,這能避免在測試方法中再寫文檔。
-
測試之間應該是孤立的。不要與真實地數據庫或網絡進行交互。使用單獨的測試數據庫,測試完即可銷毀,或者是使用模擬對象。
-
使用工廠模式,而不是fixture。
-
別讓不完整的測試通過,否則你就有可能忘記。你應該加上一些占位語句,比如
assert False, "TODO: finish me"
。
單元測試
-
每次聚焦一個很小的功能點。
-
運行速度要快,但是速度慢總比不測試好。
-
通常,每一個類或模型都應該有一個測試用例類。
import unittest
import factoriesclass PersonTest(unittest.TestCase):
def setUp(self):
self.person = factories.PersonFactory()def test_has_age_in_dog_years(self):
self.assertEqual(self.person.dog_years, self.person.age / 7)
功能測試
功能測試是更高層次的測試,更接近最終用戶如何與應用交互這一層面。通常用在網絡應用與圖形應用測試。
-
按照場景撰寫測試。測試用例的測試方法命名應該看上去像場景描述。
-
在編寫代碼之前,通過注釋說明具體場景信息。
import unittest
class TestAUser(unittest.TestCase):
def test_can_write_a_blog_post(self):
# Goes to the her dashboard
...
# Clicks "New Post" ... # Fills out the post form ... # Clicks "Submit" ... # Can see the new post ...
請注意,測試用例的類名稱和測試方法的名稱放在一起,就像是“測試一名用戶能否發(fā)布博文”。
本文受到下列資料的啟發(fā)...
-
以及其他諸多資料