PEP介紹
PEP是 Python Enhancement Proposal 的縮寫,是Python增強(qiáng)建議書的意思。
Python的代碼風(fēng)格由PEP 8描述。這個文檔描述了Python編程風(fēng)格的方方面面。在遵守這個文檔的條件下,不同程序員編寫的Python代碼可以保持最大程度的相似風(fēng)格。這樣就易于閱讀,易于在程序員之間交流。
命名規(guī)則
不同的命名風(fēng)格
有許多不同的命名風(fēng)格。以下的有助于辨認(rèn)正在使用的命名風(fēng)格,這獨(dú)立于它們的作用。
- 小寫串 (lowercase)
- 帶下劃線的小寫串 (lower_case_with_underscores)
- 大寫串 (UPPERCASE)
- 帶下劃線的大寫串 (UPPER_CASE_WITH_UNDERSCORES)
- 首字母大寫單詞串 (CapitalizedWords) (或 CapWords、CamelCase,因其字母看起來錯落有致,故得此名)
注意: 在CapWords中使用縮寫,需要把縮寫的所有字母大寫。故HTTPServerError比HttpServerError更好。- 混合大小寫串 (mixedCase) (與首字母大寫串不同之處在于第一個字符是小寫的!)
- 帶下劃線的首字母大寫串 (Capitalized_Words_With_Underscores) (丑陋!)
避免采用的名字
決不能使用字母'l'(L的小寫字母)、'O'(o的大寫字母)、'I'(i的大寫字母)) 作為單個字符的變量名。
在一些字體中,這些字符不能與數(shù)字1和0區(qū)別開。當(dāng)想要使用'l'時,用'L'代替它。
包和模塊名(Package and Module Names)
模塊名應(yīng)該是簡短的、全部小寫的名字??梢栽谀K名中使用下劃線以提高可讀性。Python包名也應(yīng)該是簡短的、全部小寫的名字,盡管不推薦使用下劃線。
因?yàn)槟K名被映射到文件名,有些文件系統(tǒng)大小寫不敏感并且截短長名字,所以把 模塊名選擇為相當(dāng)短就很重要了——這在Unix上不是問題,但當(dāng)把代碼遷移到Mac、Windows或DOS上時,就可能是個問題了。
當(dāng)一個用C或C++寫的擴(kuò)展模塊,有一個伴隨的Python模塊來提供一個更高層(例如,更面向?qū)ο?的接口時,C/C++ 模塊名有一個前導(dǎo)下劃線 (如:_socket)。
類名(Class Names)
幾乎沒有例外,類名使用首字母大寫單詞串(CapWords)的約定。內(nèi)部使用的類使用一個額外的前導(dǎo)下劃線。
異常名 (Exception Names)
因?yàn)楫惓?yīng)該是類,故類命名約定也適用于異常。然而,你應(yīng)該對異常名添加后綴"Error"(如果該異常的確是一個錯誤)。
全局變量名(Global Variable Names)
(我們希望這些變量只打算用于一個模塊內(nèi)部)。
對設(shè)計(jì)為通過"from M import "來使用的模塊,應(yīng)采用all機(jī)制來防止導(dǎo)出全局變量;或者使用舊的約定,為該類全局變量加一個前導(dǎo)下劃線(可能你想表明這些全局變量是只限制在該模塊內(nèi)部使用,"module non-public")。
補(bǔ)充:
在python的module中,可以使用 all 函數(shù)來定義這個module像其他引用自己的module導(dǎo)入的變量:
__all__ = ['bar', 'baz']
waz = 5
bar = 10
當(dāng)另一個模塊中使用import *聲明,waz和bar變量不會被導(dǎo)入,all可以隱藏不想被import的默認(rèn)值。
函數(shù)名(Function Names)
函數(shù)名應(yīng)該為小寫,必要時可用下劃線分隔單詞以增加可讀性。
混合大小寫 (mixedCase) 僅被允許用于這種風(fēng)格已經(jīng)占優(yōu)勢的上下文 (如: threading.py),以便保持向后兼容。
函數(shù)和方法的參數(shù)(Function and method arguments)
對實(shí)例的方法,總是用'self'做第一個參數(shù)。
對類的方法,總是用'cls'做第一個參數(shù)。
(如果函數(shù)的參數(shù)名與保留關(guān)鍵字沖突,在參數(shù)名后加一個下劃線,比用縮寫、錯誤的拼寫要好。因此"print_"比 "prnt"好。也許使用同義詞來避免沖突更好)
補(bǔ)充:
python的類中,普通方法的第一個參數(shù)需要是self,它表示一個具體的實(shí)例本身;如果用了staticmethod,那么就可以無視這個self,而將這個方法當(dāng)成一個普通的函數(shù)使用;而對于classmethod,它的第一個參數(shù)不是self,是cls,它表示這個類本身。
>>> class A(object):
def foo1(self):
print "Hello",self
@staticmethod
def foo2():
print "hello"
@classmethod
def foo3(cls):
print "hello",cls
>>> a = A()
>>> a.foo1() #最常見的調(diào)用方式,但與下面的方式相同
Hello <__main__.A object at 0x9f6abec>
>>> A.foo1(a) #這里傳入實(shí)例a,相當(dāng)于普通方法的self
Hello <__main__.A object at 0x9f6abec>
>>> A.foo2() #這里,由于靜態(tài)方法沒有參數(shù),故可以不傳東西
hello
>>> A.foo3() #這里,由于是類方法,因此,它的第一個參數(shù)為類本身。
hello <class '__main__.A'>
>>> A #可以看到,直接輸入A,與上面那種調(diào)用返回同樣的信息。
<class '__main__.A'>
方法名和實(shí)例變量(Method Names and Instance Variables)
采用函數(shù)命名規(guī)則:小寫單詞,必要時可用下劃線分隔單詞以增加可讀性。
僅對 non-public 方法和實(shí)例變量采用一個前導(dǎo)下劃線。
為避免與子類命名沖突,采用兩個前導(dǎo)下劃線來觸發(fā) Python 的命名重整規(guī)則。
Python用類名重整這些名字:如果類Foo有一個屬性名為__a,它不能以Foo.__a訪問(執(zhí)著的用戶還是可以通過Foo._Foo__a得到訪問權(quán))。通常,雙 前導(dǎo)下劃線僅被用來避免與基類的屬性發(fā)生名字沖突。
謹(jǐn)記python特色的命名慣例
- 公開屬性應(yīng)該沒有前導(dǎo)下劃線
- 如果公開屬性名和保留關(guān)鍵字沖突,在你的屬性名后添加一個后置下劃線
- 對簡單的公開數(shù)據(jù)屬性 (data attribute),最好只暴露屬性名,沒有復(fù)雜的訪問/修改方法
謹(jǐn)記Python為將來增強(qiáng)提供了一條容易的途徑,你應(yīng)該發(fā)現(xiàn)簡單數(shù)據(jù)屬性需要增加功能行為。在那種情況,用特性(properties)把功能實(shí)現(xiàn)隱藏在簡單數(shù)據(jù)屬性訪問語法后面。- 以單一下劃線的變量名(_X)不會被from module import *語句導(dǎo)入。一個前導(dǎo)下劃線的函數(shù)是私有函數(shù)。
Python 中不存在私有變量一說,若是遇到需要保護(hù)的變量,使用小寫和一個前導(dǎo)下劃線。但這只是程序員之間的一個約定,用于警告說明這是一個私有變量,外部類不要去訪問它。但實(shí)際上,外部類還是可以訪問到這個變量。- 前后有兩個下劃線的變量名(X)是系統(tǒng)定義的變量名,對解釋器有特殊意義。包括兩個前導(dǎo)下劃線,兩個后置下劃線的函數(shù)名,這種風(fēng)格只應(yīng)用于特殊函數(shù),比如操作符重載等。
- 以兩個下劃線開頭,但結(jié)尾沒有兩個下劃線的變量名(__X)是類的本地變量
代碼布局
縮進(jìn)(Indentation)
每級縮進(jìn)用 4 個空格。
絕不要混合使用 tab 和空格。
最流行的 Python 縮進(jìn)方式是僅使用空格,其次是僅使用制表符?;旌现票矸涂?格縮進(jìn)的代碼將被轉(zhuǎn)換成僅使用空格。調(diào)用 Python 命令行解釋器時使用 -t 選項(xiàng), 可對代碼中不合法的混用制表符和空格發(fā)出警告 (warnings)。使用 -tt 時警告將變 成錯誤。這些選項(xiàng)是被高度推薦的。
對新項(xiàng)目,強(qiáng)烈推薦只用空格,而不是用tabs。大多數(shù)編輯器擁有使之易于實(shí)現(xiàn)的功能。
最大行寬(Maximum Line Length)
限制所有行的最大行寬為79字符。
折疊長行的首選方法是使用Python支持的圓括號、方括號(brackets)和花括號(braces)內(nèi)的行延續(xù)。如果需要,你可以在表達(dá)式周圍增加一對額外的圓括號,但是有時使用反斜杠看起來更好。確認(rèn)恰當(dāng)?shù)乜s進(jìn)了延續(xù)的行。
class Rectangle(Blob):
def __init__(self, width, height,
color='black', emphasis=None, highlight=0):
if width == 0 and height == 0 and \
color == 'red' and emphasis == 'strong' or \ highlight > 100:
raise ValueError("sorry, you lose")
if width == 0 and height == 0 and (color == 'red' or
emphasis is None):
raise ValueError("I don't think so")
Blob.__init__(self, width, height,
color, emphasis, highlight)
空行(Blank Lines)
用兩行空行分割頂層函數(shù)和類的定義。
類內(nèi)方法的定義用單個空行分割。
在函數(shù)中使用空行時,請謹(jǐn)慎的用于表示一個邏輯段落。
導(dǎo)入 (Imports)
- 通常應(yīng)該在單獨(dú)的行中導(dǎo)入:
Yes: import os
import sys
No: import sys, os
但是這樣也是可以的:
from subprocess import Popen, PIPE
Imports通常被放置在文件的頂部,僅在模塊注釋和文檔字符串之后,在模塊的全局變量和常量之前。
Imports應(yīng)該按照如下順序成組安放:
- 標(biāo)準(zhǔn)庫的導(dǎo)入
- 相關(guān)的第三方包的導(dǎo)入
- 本地應(yīng)用/庫的特定導(dǎo)入
對于內(nèi)部包的導(dǎo)入是非常不推薦使用相對導(dǎo)入的。對所有導(dǎo)入總是使用包的絕對路徑
從一個包含類的模塊中導(dǎo)入類時,通??梢詫懗蛇@樣:
from myclass import MyClass
from foo.bar.yourclass import YourClass
如果這樣寫導(dǎo)致了本地名字沖突,那么就這樣寫:
import myclass
import foo.bar.yourclass
并使用"myclass.MyClass" and "foo.bar.yourclass.YourClass"
在表達(dá)式和語句中的空格(Whitespace in Expressions and Statements)
- 緊挨著圓括號、方括號和花括號:
Yes: spam(ham[1], {eggs: 2})
No: spam( ham[ 1 ], { eggs: 2 } ) - 緊貼在逗號、分號或冒號前:
Yes: if x == 4: print x, y; x, y = y, x
No: if x == 4 : print x , y ; x , y = y , x - 緊貼著函數(shù)調(diào)用的參數(shù)列表前的開式括號:
Yes: spam(1)
No: spam (1) - 緊貼在索引或切片 (indexing or slicing) 開始的開式括號前:
Yes: dct['key'] = lst[index]
No: dct ['key'] = lst [index] - 在賦值 (或其他) 運(yùn)算符周圍的用于和其他語句對齊的一個以上的空格:
Yes:
x = 1
y = 2
long_variable = 3
No:
x = 1
y = 2
long_variable = 3
注釋(Comments)
同代碼不一致的注釋比沒注釋更差。當(dāng)代碼修改時,始終優(yōu)先更新注釋!
注釋應(yīng)該是完整的句子。如果注釋是一個短語或句子,首字母應(yīng)該大寫,除非它是一個以小寫字母開頭的標(biāo)識符(永遠(yuǎn)不要修改標(biāo)識符的大小寫)。
如果注釋很短,可以省略末尾的句號。注釋塊通常由一個或多個段落組成,段落是由完整的句子構(gòu)成的,每個句子應(yīng)該以句號結(jié)尾。
你應(yīng)該在結(jié)束語句的句點(diǎn)(a sentence-ending period)后使用兩個空格。
非英語國家的Python程序員:請用英語書寫你的注釋,除非你120%的確信代碼永遠(yuǎn)不會被不懂你的語言的人閱讀。
注釋塊(Block Comments)
注釋塊通常應(yīng)用于跟隨其后的一些 (或者全部) 代碼,并和這些代碼有著相同的縮進(jìn) 層次。注釋塊中每行以 '#' 和一個空格開始 (除非它是注釋內(nèi)的縮進(jìn)文本)。
注釋塊內(nèi)的段落以僅含單個 '#' 的行分割。
行內(nèi)注釋(Inline Comments)
節(jié)儉使用行內(nèi)注釋。
一個行內(nèi)注釋是和語句在同一行的注釋。行內(nèi)注釋應(yīng)該至少用兩個空格和語句分開。 它們應(yīng)該以一個 '#' 和單個空格開始。
行內(nèi)注釋不是必需的,事實(shí)上,如果說的是顯而易見事,還會使人分心。不要這樣做 :
x = x + 1 # Increment x
但是有時,這樣是有益的:
x = x + 1 # Compensate for border
參考資料
如何使用Pylint來規(guī)范Python代碼風(fēng)格
PEP 8 - Style Guide for Python Code
轉(zhuǎn)載請注明作者Jason Ding及其出處
Github博客主頁(http://jasonding1354.github.io/)
CSDN博客(http://blog.csdn.net/jasonding1354)
簡書主頁(http://www.lxweimin.com/users/2bd9b48f6ea8/latest_articles)