Python開發編碼規範(轉)


這篇文檔所給出的編碼約定適用於在主要的Python發佈版本中組成標準庫的Python 代碼,請查閱相關的關於在Python的C實現中C代碼風格指南的描述。

這 篇文檔改編自Guido最初的《Python風格指南》一文,並從《Barry's style guide》中添加了部分內容。在有衝突的地方,Guide的風格規則應該是符合本PEP的意圖(譯註:指當有衝突時,應以Guido風格爲準)。這篇 PEP仍然尚未完成(實際上,它可能永遠都不會完成)。

在這篇風格指導中的一致性是重要的。在一個項目內的一致性更重要。在一個模塊或函數內的一致性最重要。但最重要的是:知道何時會不一致——有時只是沒有實施風格指導。當出現疑惑時,運用你的最佳判斷,看看別的例子,然後決定怎樣看起來更好。並且要不恥下問!

打破一條既定規則的兩個好理由:

(1) 當應用這個規則是將導致代碼可讀性下降,即便對某人來說,他已經習慣於按這條規則來閱讀代碼了。

(2) 爲了和周圍的代碼保持一致而打破規則(也許是歷史原因),雖然這也是個清除其它混亂的好機會(真正的XP風格)。

代碼的佈局

縮進

使用Emacs的Python-mode的默認值:4個空格一個縮進層次。對於確實古老的代碼,你不希望產生混亂,可以繼續使用8空格的製表符(8-space tabs)。Emacs Python-mode自動發現文件中主要的縮進層次,依此設定縮進參數。

製表符還是空格

永 遠不要混用製表符和空格。最流行的Python縮進方式是僅使用空格,其次是僅使用製表符,混合着製表符和空格縮進的代碼將被轉換成僅使用空格。(在 Emacs中,選中整個緩衝區,按ESC-x去除製表符。)調用Python命令行解釋器時使用-t選項,可對代碼中不合法得混合製表符和空格發出警告, 使用-tt時警告將變成錯誤。這些選項是被高度推薦的。

對於新的項目,強烈推薦僅使用空格而不是製表符。許多編輯器擁有使之易於實現的功能(在Emacs中,確認indent-tabs-mode是nil)。

行的最大長度

周 圍仍然有許多設備被限制在每行80字符:而且,窗口限制在80個字符。使將多個窗口並排放置成爲可能。在這些設備上使用默認的摺疊方式看起來有點醜陋。因 此,請將所有行限制在最大79字符(Emacs準確得將行限制爲長80字符),對順序排放的大塊文本(文檔字符串或註釋),推薦將長度限制在72字符。

摺疊長行的首選方法是使用Pyhon支持的圓括號,方括號和花括號內的行延續。如果需要,你可以在表達式周圍增加一對額外的圓括號,但是有時使用反斜槓看起來更好,確認恰當得縮進了延續的行。

Emacs的Python-mode正確得完成了這些。一些例子:

#!Python

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)

空行

用兩行空行分割頂層函數和類的定義,類內方法的定義用單個空行分割,額外的空行可被用於(保守的)分割相關函數組成的羣,在一組相關的單句中間可以省略空行。(例如:一組啞元素)。

當 空行用於分割方法的定義時,在‘class’行和第一個方法定義之間也要有一個空行。在函數中使用空行時,請謹慎的用於表示一個邏輯段落。Python接 受contol-L(即^L)換頁符作爲空格:Emacs(和一些打印工具),視這個字符爲頁面分割符,因此在你的文件中,可以用他們來爲相關片段分頁。

編碼

Python核心發佈中的代碼必須始終使用ASCII或Latin-1編碼(又名 ISO-8859-1),使用ASCII的文件不必有編碼cookie,Latin-1僅當註釋或文檔字符串涉及作者名字需要Latin-1時才被使用:

另外使用\x轉義字符是在字符串中包含非ASCII(non-ASCII)數據的首選方法。

作爲PEP 263實現代碼的測試套件的部分文件是個例外。

導入

通常應該在單獨的行中導入(Imports),例如:

No:import sys, os

Yes:import sys

import os

但是這樣也是可以的:

from types import StringType, ListType

Imports 通常被放置在文件的頂部,僅在模塊註釋和文檔字符串之後,在模塊的全局變量和常量之前。Imports應該有順序地成組安放:

1、標準庫的導入(Imports )

2、相關的主包(major package)的導入(即,所有的email包在隨後導入)

3、特定應用的導入(imports)

你應該在每組導入之間放置一個空行,對於內部包的導入是不推薦使用相對導入的,對所有導入都要使用包的絕對路徑。

從一個包含類的模塊中導入類時,通常可以寫成這樣:

from MyClass import MyClass

from foo.bar.YourClass import YourClass

如果這樣寫導致了本地名字衝突,那麼就這樣寫

import MyClass

import foo.bar.YourClass

即使用"MyClass.MyClass"和"foo.bar.YourClass.YourClass"

表達式和語句中的空格

Guido不喜歡在以下地方出現空格:

緊挨着圓括號,方括號和花括號的,如:"spam( ham[ 1 ],{ eggs:2 } )"。要始終將它寫成"spam(ham[1],{eggs: 2})"。

緊貼在逗號,分號或冒號前的,如:

"if x == 4:print x,y:x,y = y,x"。要始終將它寫成

"if x == 4:print x,y:x,y = y,x"。

緊貼着函數調用的參數列表前開式括號(open parenthesis )的,如"spam (1)"。要始終將它寫成"spam(1)"。

緊貼在索引或切片,開始的開式括號前的,如:

"dict ['key'] = list [index]"。要始終將它寫成"dict['key'] = list[index]"。

在賦值(或其它)運算符周圍的用於和其它並排的一個以上的空格,如:

#!Python

x= 1

y= 2

long_variable = 3

要始終將它寫成

#!Python

x = 1

y = 2

long_variable = 3

(不要對以上任意一條和他爭論——Guido 養成這樣的風格超過20年了。)

其它建議

始終在這些二元運算符兩邊放置一個空格:賦值(=), 比較(==,<,>,!=,<>,<=, >=,in,not in,is,is not),布爾運算 (and,or,not)。

按你的看法在算術運算符周圍插入空格。 始終保持二元運算符兩邊空格的一致。

一些例子:

#!Python

i = i+1

submitted = submitted + 1

x = x*2 - 1

hypot2 = x*x + y*y

c = (a+b) * (a-b)

c = (a + b) * (a - b)

不要在用於指定關鍵字參數或默認參數值的'='號周圍使用空格,例如:

#!Python

def complex(real, imag=0。0):

return magic(r=real, i=imag)

不要將多條語句寫在同一行上:

No: if foo == 'blah':do_blah_thing()

Yes:if foo == 'blah':

do_blah_thing()

No:do_one():do_two():do_three()

Yes: do_one()

do_two()

do_three()

註釋

同代碼不一致的註釋比沒註釋更差。當代碼修改時,始終優先更新註釋!註釋應該是完整的句子,如果註釋是一個短語或句子,首字母應該大寫,除非他是一個以小寫字母開頭的標識符(永遠不要修改標識符的大小寫)。

如果註釋很短,最好省略末尾的句號。註釋塊通常由一個或多個由完整句子構成的段落組成,每個句子應該以句號結尾。你應該在句末,句號後使用兩個空格,以便使Emacs的斷行和填充工作協調一致。

用英語書寫時,斷詞和空格是可用的。非英語國家的Python程序員:請用英語書寫你的註釋,除非你120%的確信這些代碼不會被不懂你的語言的人閱讀。

註釋塊

註釋塊通常應用於跟隨着一些(或者全部)代碼並和這些代碼有着相同的縮進層次。註釋塊中每行以‘#’和一個空格開始(除非他是註釋內的縮進文本)。註釋塊內的段落以僅含單個‘#’的行分割。註釋塊上下方最好有一空行包圍(或上方兩行下方一行,對一個新函數定義段的註釋)。

行內註釋

一個行內註釋是和語句在同一行的註釋,行內註釋應該謹慎適用,行內註釋應該至少用兩個空格和語句分開,它們應該以'#'和單個空格開始。

x = x+1 # Increment x

如果語意是很明瞭的,那麼行內註釋是不必要的,事實上是應該被移除的。不要這樣寫:

x = x+1 # Increment x

x = x+1 # Compensate for border

但是有時,這樣是有益的:

x = x+1 # Compensate for border

文檔字符串

應該一直遵守編寫好的文檔字符串的約定PEP 257 [3]。爲所有公共模塊,函數,類和方法編寫文檔字符串。文檔字符串對非公開的方法不是必要的,但你應該有一個描述這個方法做什麼的註釋。這個註釋應該在"def"這行後。

PEP 257 描述了好的文檔字符串的約定。一定注意,多行文檔字符串結尾的"""應該單獨成行,例如:

"""Return a foobang

Optional plotz says to frobnicate the bizbaz first。

"""

對單行的文檔字符串,結尾的"""在同一行也可以。

版本註記

如果你要將RCS或CVS的雜項(crud)包含在你的源文件中,按如下做。

#!Python

__version__ = "$Revision: 1。4 $"

# $Source: E:/cvsroot/Python_doc/pep8。txt,v $

這個行應該包含在模塊的文檔字符串之後,所有代碼之前,上下用一個空行分割。

命名約定

Python庫的命名約定有點混亂,所以我們將永遠不能使之變得完全一致,不過還是有公認的命名規範的。新的模塊和包(包括第三方的框架)必須符合這些標準,但對已有的庫存在不同風格的,保持內部的一致性是首選的。

描述:命名風格

有許多不同的命名風格。以下的有助於辨認正在使用的命名風格,獨立於它們的作用。 以下的命名風格是衆所周知的:

b (單個小寫字母)

B (單個大寫字母)

Lowercase(小寫)

lower_case_with_underscores(有下劃線的小寫)

UPPERCASE(大寫)

UPPER_CASE_WITH_UNDERSCORES(有下劃線的大寫)

CapitalizedWords (或 CapWords,CamelCase這樣命名是因爲可從字母的大小寫分出單詞。這有時也被當作StudlyCaps。

mixedCase (與CapitalizedWords的不同在於首字母小寫!)

Capitalized_Words_With_Underscores(有下劃線的首字母大寫) (醜陋!)

還有用短的特別前綴將相關的名字聚合在一起的風格。這在Python中不常用,但是出於完整性要提一下,例如,os.stat()函數返回一個元組,他的元素傳統上說名如st_mode, st_size,st_mtime等等。

X11庫的所有公開函數以X開頭。(在Python中,這個風格通常認爲是不必要的,因爲屬性和方法名以對象作前綴,而函數名以模塊名作前綴。)

另外,以下用下劃線作前導或結尾的特殊形式是被公認的(這些通常可以和任何習慣組合):

_single_leading_underscore(單個下劃線作前導):弱的“內部使用(internal use)”標誌。 (例如,“from M import *”不會導入以下劃線開頭的對象)。

single_trailing_underscore_(單個下劃線結尾): 用於避免與Python關鍵詞的衝突,例如:“Tkinter.Toplevel(master,class_='ClassName')”。

_double_leading_underscore(雙下劃線):從Python 1.4起爲類私有名。

_double_leading_and_trailing_underscore_:“magic” 對象或屬性,存在於用戶控制的(user-controlled)名字空間,例如:_init_, _import_ 或_file_。有時它們被用戶定義用於觸發某個魔法行爲(例如:運算符重載):有時被構造器插入,以便自己使用或爲了調試。因此,在未來的版本中,構造 器(鬆散得定義爲Python解釋器和標準庫)可能打算建立自己的魔法屬性列表,用戶代碼通常應該限制將這種約定作爲己用。欲成爲構造器的一部分的用戶代 碼可以在下滑線中結合使用短前綴,例如:

_bobo_magic_attr__。

說明:命名約定

應避免的名字。永遠不要用字符‘l’(小寫字母el(就是讀音,下同)),‘O’(大寫字母oh),或‘I’(大寫字母eye)作爲單字符的變量名。在某些字體中這些字符不能與數字1和0分辨。試着在使用‘l’時用‘L’代替。

模塊名

模塊應該是不含下劃線的,簡短的,小寫的名字。因爲模塊名被映射到文件名,有些文件系統大小寫不敏感並且截短長名字,模塊名被選爲相當短是重要的,這在Unix上不是問題,但當代碼傳到Mac或Windows上就可能是個問題了。

當用C或C++編寫的擴展模塊有一個伴隨Python模塊提供高層(例如進一步的面向對象)接口時,C/C++模塊有下劃線前導(如:_socket)。Python包應該是不含下劃線的,簡短的,全小寫的名字。

類名

幾乎不出意料,類名使用CapWords約定。內部使用的類外加一個前導下劃線。

異常名

如 果模塊對所有情況定義了單個異常,它通常被叫做“error”或“Error”。似乎內建(擴展)的模塊使用“error”(例如:os.error), 而Python模塊通常用“Error” (例如:xdrlib.Error)。趨勢似乎是傾向使用CapWords異常名。

全局變量名

(讓我們祈禱這些變量僅在一個模塊的內部有意義)

這些約定和在函數中的一樣。模塊是被設計爲通過“from M import *”來使用的,必須用一個下劃線作全局變量(及內部函數和類)的前綴防止其被導出(exporting)。

函數名

函數名應該爲小寫,可能用下劃線風格單詞以增加可讀性。mixedCase僅被允許用於這種風格已經佔優勢的上下文(如:threading.py),以便保持向後兼容。

方法名和實例變量

這段大體上和函數相同:通常使用小寫單詞,必要時用下劃線分隔增加可讀性。僅爲不打算作爲類的公共界面的內部方法和實例使用一個前導下劃線,Python不強制要求這樣:它取決於程序員是否遵守這個約定。

使用兩個前導下劃線以表示類私有的名字,Python將這些名字和類名連接在一起:

如果類Foo有一個屬性名爲_a,它不能以Foo._a訪問。(固執的用戶還是可以通過Foo._Foo__a得到訪問權。)

通常雙前導下劃線僅被用於避免含子類的類中的屬性名的名字衝突。

繼承的設計

始終要確定一個類中的方法和實例變量是否要被公開。通常,永遠不要將數據變量公開,除非你實現的本質上只是記錄,人們幾乎總是更喜歡代之給出一個函數作爲類的界面(Python 2.2 的一些開發者在這點上做得非常漂亮)。

同 樣,確定你的屬性是否應爲私有的。私有和非私有的區別在於模板將永遠不會對原有的類(導出類)有效,而後者可以。你應該在大腦中就用繼承設計好了你的類, 私有屬性必須有兩個前導下劃線,無後置下劃線,非公有屬性必須有一個前導下劃線,無後置下劃線,公共屬性沒有前導和後置下劃線,除非它們與保留字衝突,在 此情況下,單個後置下劃線比前置或混亂的拼寫要好,例如:class_優於klass。

最後一點有些爭議:如果相比class_你更喜歡klass,那麼這只是一致性問題。

設計建議

單 個元素(singletons)的比較,如None 應該永遠用:‘is’或‘is not’來做。當你本意是“if x is not None”時,對寫成“if x”要小心。例如當你測試一個默認爲None的變量或參數是否被設置爲其它值時,這個值也許在布爾上下文(Boolean context)中是false!

基於類的異常總是好過基於字符串的異常。模塊和包應該定義它們自己的域內特定的基異常類,基類應該是內建的Exception類的子類。還始終包含一個類的文檔字符串。例如:

#!Python

class MessageError(Exception):

"""Base class for errors in the email package。"""

使 用字符串方法(methods)代替字符串模塊,除非必須向後兼容Python 2.0以前的版本。字符串方法總是非常快,而且和unicode字符串共用同樣的API(應用程序接口)在檢查前綴或後綴時避免對字符串進行切片。用 startswith()和endswith()代替,因爲它們是明確的並且錯誤更少。例如:

No: if foo[:3] == 'bar':

Yes: if foo。startswith('bar'):

例外是如果你的代碼必須工作在Python 1.5.2 (但是我們希望它不會發生!),對象類型的比較應該始終用isinstance()代替直接比較類型,例如:

No: if type(obj) is type(1):

Yes: if isinstance(obj, int):

檢查一個對象是否是字符串時,緊記它也可能是unicode字符串!在Python 2.3,str和unicode有公共的基類,basestring,所以你可以這樣做:

if isinstance(obj, basestring):

在Python 2.2類型模塊爲此定義了StringTypes類型,例如:

#!Python

from types import StringTypes

if isinstance(obj, StringTypes):

在Python 2.0和2.1,你應該這樣做:

#!Python

from types import StringType, UnicodeType

if isinstance(obj, StringType) or \

isinstance(obj, UnicodeType) :

對 序列,(字符串,列表,元組),使用空列表是false這個事實,因此“if not seq”或“if seq”比“if len(seq)”或“if not len(seq)”好。書寫字符串文字時不要依賴於有意義的後置空格。這種後置空格在視覺上是不可辨別的,並且有些編輯器(特別是近 來,reindent.py)會將它們修整掉。不要用==來比較布爾型的值以確定是True或False(布爾型是Pythn 2.3中新增的)

No: if greeting == True:

Yes: if greeting:

No: if greeting == True:

Yes: if greeting:

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