Python開發(fā)編碼規(guī)范
更新時(shí)間:2006年09月08日 00:00:00 作者:
這篇文檔所給出的編碼約定適用于在主要的Python發(fā)布版本中組成標(biāo)準(zhǔn)庫(kù)的Python 代碼,請(qǐng)查閱相關(guān)的關(guān)于在Python的C實(shí)現(xiàn)中C代碼風(fēng)格指南的描述。
這篇文檔改編自Guido最初的《Python風(fēng)格指南》一文,并從《Barry's style guide》中添加了部分內(nèi)容。在有沖突的地方,Guide的風(fēng)格規(guī)則應(yīng)該是符合本PEP的意圖(譯注:指當(dāng)有沖突時(shí),應(yīng)以Guido風(fēng)格為準(zhǔn))。這篇PEP仍然尚未完成(實(shí)際上,它可能永遠(yuǎn)都不會(huì)完成)。
在這篇風(fēng)格指導(dǎo)中的一致性是重要的。在一個(gè)項(xiàng)目?jī)?nèi)的一致性更重要。在一個(gè)模塊或函數(shù)內(nèi)的一致性最重要。但最重要的是:知道何時(shí)會(huì)不一致——有時(shí)只是沒(méi)有實(shí)施風(fēng)格指導(dǎo)。當(dāng)出現(xiàn)疑惑時(shí),運(yùn)用你的最佳判斷,看看別的例子,然后決定怎樣看起來(lái)更好。并且要不恥下問(wèn)!
打破一條既定規(guī)則的兩個(gè)好理由:
(1) 當(dāng)應(yīng)用這個(gè)規(guī)則是將導(dǎo)致代碼可讀性下降,即便對(duì)某人來(lái)說(shuō),他已經(jīng)習(xí)慣于按這條規(guī)則來(lái)閱讀代碼了。
(2) 為了和周圍的代碼保持一致而打破規(guī)則(也許是歷史原因),雖然這也是個(gè)清除其它混亂的好機(jī)會(huì)(真正的XP風(fēng)格)。
代碼的布局
縮進(jìn)
使用Emacs的Python-mode的默認(rèn)值:4個(gè)空格一個(gè)縮進(jìn)層次。對(duì)于確實(shí)古老的代碼,你不希望產(chǎn)生混亂,可以繼續(xù)使用8空格的制表符(8-space tabs)。Emacs Python-mode自動(dòng)發(fā)現(xiàn)文件中主要的縮進(jìn)層次,依此設(shè)定縮進(jìn)參數(shù)。
制表符還是空格
永遠(yuǎn)不要混用制表符和空格。最流行的Python縮進(jìn)方式是僅使用空格,其次是僅使用制表符,混合著制表符和空格縮進(jìn)的代碼將被轉(zhuǎn)換成僅使用空格。(在Emacs中,選中整個(gè)緩沖區(qū),按ESC-x去除制表符。)調(diào)用Python命令行解釋器時(shí)使用-t選項(xiàng),可對(duì)代碼中不合法得混合制表符和空格發(fā)出警告,使用-tt時(shí)警告將變成錯(cuò)誤。這些選項(xiàng)是被高度推薦的。
對(duì)于新的項(xiàng)目,強(qiáng)烈推薦僅使用空格而不是制表符。許多編輯器擁有使之易于實(shí)現(xiàn)的功能(在Emacs中,確認(rèn)indent-tabs-mode是nil)。
行的最大長(zhǎng)度
周圍仍然有許多設(shè)備被限制在每行80字符:而且,窗口限制在80個(gè)字符。使將多個(gè)窗口并排放置成為可能。在這些設(shè)備上使用默認(rèn)的折疊方式看起來(lái)有點(diǎn)丑陋。因此,請(qǐng)將所有行限制在最大79字符(Emacs準(zhǔn)確得將行限制為長(zhǎng)80字符),對(duì)順序排放的大塊文本(文檔字符串或注釋),推薦將長(zhǎng)度限制在72字符。
折疊長(zhǎng)行的首選方法是使用Pyhon支持的圓括號(hào),方括號(hào)和花括號(hào)內(nèi)的行延續(xù)。如果需要,你可以在表達(dá)式周圍增加一對(duì)額外的圓括號(hào),但是有時(shí)使用反斜杠看起來(lái)更好,確認(rèn)恰當(dāng)?shù)每s進(jìn)了延續(xù)的行。
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)
空行
用兩行空行分割頂層函數(shù)和類的定義,類內(nèi)方法的定義用單個(gè)空行分割,額外的空行可被用于(保守的)分割相關(guān)函數(shù)組成的群,在一組相關(guān)的單句中間可以省略空行。(例如:一組啞元素)。
當(dāng)空行用于分割方法的定義時(shí),在‘class'行和第一個(gè)方法定義之間也要有一個(gè)空行。在函數(shù)中使用空行時(shí),請(qǐng)謹(jǐn)慎的用于表示一個(gè)邏輯段落。Python接受contol-L(即^L)換頁(yè)符作為空格:Emacs(和一些打印工具),視這個(gè)字符為頁(yè)面分割符,因此在你的文件中,可以用他們來(lái)為相關(guān)片段分頁(yè)。
編碼
Python核心發(fā)布中的代碼必須始終使用ASCII或Latin-1編碼(又名 ISO-8859-1),使用ASCII的文件不必有編碼cookie,Latin-1僅當(dāng)注釋或文檔字符串涉及作者名字需要Latin-1時(shí)才被使用:
另外使用\x轉(zhuǎn)義字符是在字符串中包含非ASCII(non-ASCII)數(shù)據(jù)的首選方法。
作為PEP 263實(shí)現(xiàn)代碼的測(cè)試套件的部分文件是個(gè)例外。
導(dǎo)入
通常應(yīng)該在單獨(dú)的行中導(dǎo)入(Imports),例如:
No:import sys, os
Yes:import sys
import os
但是這樣也是可以的:
from types import StringType, ListType
Imports 通常被放置在文件的頂部,僅在模塊注釋和文檔字符串之后,在模塊的全局變量和常量之前。Imports應(yīng)該有順序地成組安放:
1、標(biāo)準(zhǔn)庫(kù)的導(dǎo)入(Imports )
2、相關(guān)的主包(major package)的導(dǎo)入(即,所有的email包在隨后導(dǎo)入)
3、特定應(yīng)用的導(dǎo)入(imports)
你應(yīng)該在每組導(dǎo)入之間放置一個(gè)空行,對(duì)于內(nèi)部包的導(dǎo)入是不推薦使用相對(duì)導(dǎo)入的,對(duì)所有導(dǎo)入都要使用包的絕對(duì)路徑。
從一個(gè)包含類的模塊中導(dǎo)入類時(shí),通??梢詫懗蛇@樣:
from MyClass import MyClass
from foo.bar.YourClass import YourClass
如果這樣寫導(dǎo)致了本地名字沖突,那么就這樣寫
import MyClass
import foo.bar.YourClass
即使用"MyClass.MyClass"和"foo.bar.YourClass.YourClass"
表達(dá)式和語(yǔ)句中的空格
Guido不喜歡在以下地方出現(xiàn)空格:
緊挨著圓括號(hào),方括號(hào)和花括號(hào)的,如:"spam( ham[ 1 ],{ eggs:2 } )"。要始終將它寫成"spam(ham[1],{eggs: 2})"。
緊貼在逗號(hào),分號(hào)或冒號(hào)前的,如:
"if x == 4:print x,y:x,y = y,x"。要始終將它寫成
"if x == 4:print x,y:x,y = y,x"。
緊貼著函數(shù)調(diào)用的參數(shù)列表前開式括號(hào)(open parenthesis )的,如"spam (1)"。要始終將它寫成"spam(1)"。
緊貼在索引或切片,開始的開式括號(hào)前的,如:
"dict ['key'] = list [index]"。要始終將它寫成"dict['key'] = list[index]"。
在賦值(或其它)運(yùn)算符周圍的用于和其它并排的一個(gè)以上的空格,如:
#!Python
x= 1
y= 2
long_variable = 3
要始終將它寫成
#!Python
x = 1
y = 2
long_variable = 3
(不要對(duì)以上任意一條和他爭(zhēng)論——Guido 養(yǎng)成這樣的風(fēng)格超過(guò)20年了。)
其它建議
始終在這些二元運(yùn)算符兩邊放置一個(gè)空格:賦值(=), 比較(==,<,>,!=,<>,<=, >=,in,not in,is,is not),布爾運(yùn)算 (and,or,not)。
按你的看法在算術(shù)運(yùn)算符周圍插入空格。 始終保持二元運(yùn)算符兩邊空格的一致。
一些例子:
#!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)
不要在用于指定關(guān)鍵字參數(shù)或默認(rèn)參數(shù)值的'='號(hào)周圍使用空格,例如:
#!Python
def complex(real, imag=0。0):
return magic(r=real, i=imag)
不要將多條語(yǔ)句寫在同一行上:
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()
注釋
同代碼不一致的注釋比沒(méi)注釋更差。當(dāng)代碼修改時(shí),始終優(yōu)先更新注釋!注釋應(yīng)該是完整的句子,如果注釋是一個(gè)短語(yǔ)或句子,首字母應(yīng)該大寫,除非他是一個(gè)以小寫字母開頭的標(biāo)識(shí)符(永遠(yuǎn)不要修改標(biāo)識(shí)符的大小寫)。
如果注釋很短,最好省略末尾的句號(hào)。注釋塊通常由一個(gè)或多個(gè)由完整句子構(gòu)成的段落組成,每個(gè)句子應(yīng)該以句號(hào)結(jié)尾。你應(yīng)該在句末,句號(hào)后使用兩個(gè)空格,以便使Emacs的斷行和填充工作協(xié)調(diào)一致。
用英語(yǔ)書寫時(shí),斷詞和空格是可用的。非英語(yǔ)國(guó)家的Python程序員:請(qǐng)用英語(yǔ)書寫你的注釋,除非你120%的確信這些代碼不會(huì)被不懂你的語(yǔ)言的人閱讀。
注釋塊
注釋塊通常應(yīng)用于跟隨著一些(或者全部)代碼并和這些代碼有著相同的縮進(jìn)層次。注釋塊中每行以‘#'和一個(gè)空格開始(除非他是注釋內(nèi)的縮進(jìn)文本)。注釋塊內(nèi)的段落以僅含單個(gè)‘#'的行分割。注釋塊上下方最好有一空行包圍(或上方兩行下方一行,對(duì)一個(gè)新函數(shù)定義段的注釋)。
行內(nèi)注釋
一個(gè)行內(nèi)注釋是和語(yǔ)句在同一行的注釋,行內(nèi)注釋應(yīng)該謹(jǐn)慎適用,行內(nèi)注釋應(yīng)該至少用兩個(gè)空格和語(yǔ)句分開,它們應(yīng)該以'#'和單個(gè)空格開始。
x = x+1 # Increment x
如果語(yǔ)意是很明了的,那么行內(nèi)注釋是不必要的,事實(shí)上是應(yīng)該被移除的。不要這樣寫:
x = x+1 # Increment x
x = x+1 # Compensate for border
但是有時(shí),這樣是有益的:
x = x+1 # Compensate for border
文檔字符串
應(yīng)該一直遵守編寫好的文檔字符串的約定PEP 257 [3]。為所有公共模塊,函數(shù),類和方法編寫文檔字符串。文檔字符串對(duì)非公開的方法不是必要的,但你應(yīng)該有一個(gè)描述這個(gè)方法做什么的注釋。這個(gè)注釋應(yīng)該在"def"這行后。
PEP 257 描述了好的文檔字符串的約定。一定注意,多行文檔字符串結(jié)尾的"""應(yīng)該單獨(dú)成行,例如:
"""Return a foobang
Optional plotz says to frobnicate the bizbaz first。
"""
對(duì)單行的文檔字符串,結(jié)尾的"""在同一行也可以。
版本注記
如果你要將RCS或CVS的雜項(xiàng)(crud)包含在你的源文件中,按如下做。
#!Python
__version__ = "$Revision: 1。4 $"
# $Source: E:/cvsroot/Python_doc/pep8。txt,v $
這個(gè)行應(yīng)該包含在模塊的文檔字符串之后,所有代碼之前,上下用一個(gè)空行分割。
命名約定
Python庫(kù)的命名約定有點(diǎn)混亂,所以我們將永遠(yuǎn)不能使之變得完全一致,不過(guò)還是有公認(rèn)的命名規(guī)范的。新的模塊和包(包括第三方的框架)必須符合這些標(biāo)準(zhǔn),但對(duì)已有的庫(kù)存在不同風(fēng)格的,保持內(nèi)部的一致性是首選的。
描述:命名風(fēng)格
有許多不同的命名風(fēng)格。以下的有助于辨認(rèn)正在使用的命名風(fēng)格,獨(dú)立于它們的作用。 以下的命名風(fēng)格是眾所周知的:
b (單個(gè)小寫字母)
B (單個(gè)大寫字母)
Lowercase(小寫)
lower_case_with_underscores(有下劃線的小寫)
UPPERCASE(大寫)
UPPER_CASE_WITH_UNDERSCORES(有下劃線的大寫)
CapitalizedWords (或 CapWords,CamelCase這樣命名是因?yàn)榭蓮淖帜傅拇笮懛殖鰡卧~。這有時(shí)也被當(dāng)作StudlyCaps。
mixedCase (與CapitalizedWords的不同在于首字母小寫!)
Capitalized_Words_With_Underscores(有下劃線的首字母大寫) (丑陋!)
還有用短的特別前綴將相關(guān)的名字聚合在一起的風(fēng)格。這在Python中不常用,但是出于完整性要提一下,例如,os.stat()函數(shù)返回一個(gè)元組,他的元素傳統(tǒng)上說(shuō)名如st_mode, st_size,st_mtime等等。
X11庫(kù)的所有公開函數(shù)以X開頭。(在Python中,這個(gè)風(fēng)格通常認(rèn)為是不必要的,因?yàn)閷傩院头椒詫?duì)象作前綴,而函數(shù)名以模塊名作前綴。)
另外,以下用下劃線作前導(dǎo)或結(jié)尾的特殊形式是被公認(rèn)的(這些通常可以和任何習(xí)慣組合):
_single_leading_underscore(單個(gè)下劃線作前導(dǎo)):弱的“內(nèi)部使用(internal use)”標(biāo)志。 (例如,“from M import *”不會(huì)導(dǎo)入以下劃線開頭的對(duì)象)。
single_trailing_underscore_(單個(gè)下劃線結(jié)尾): 用于避免與Python關(guān)鍵詞的沖突,例如:“Tkinter.Toplevel(master,class_='ClassName')”。
_double_leading_underscore(雙下劃線):從Python 1.4起為類私有名。
_double_leading_and_trailing_underscore_:“magic”對(duì)象或?qū)傩?,存在于用戶控制?user-controlled)名字空間,例如:_init_, _import_ 或_file_。有時(shí)它們被用戶定義用于觸發(fā)某個(gè)魔法行為(例如:運(yùn)算符重載):有時(shí)被構(gòu)造器插入,以便自己使用或?yàn)榱苏{(diào)試。因此,在未來(lái)的版本中,構(gòu)造器(松散得定義為Python解釋器和標(biāo)準(zhǔn)庫(kù))可能打算建立自己的魔法屬性列表,用戶代碼通常應(yīng)該限制將這種約定作為己用。欲成為構(gòu)造器的一部分的用戶代碼可以在下滑線中結(jié)合使用短前綴,例如:
_bobo_magic_attr__。
說(shuō)明:命名約定
應(yīng)避免的名字。永遠(yuǎn)不要用字符‘l'(小寫字母el(就是讀音,下同)),‘O'(大寫字母oh),或‘I'(大寫字母eye)作為單字符的變量名。在某些字體中這些字符不能與數(shù)字1和0分辨。試著在使用‘l'時(shí)用‘L'代替。
模塊名
模塊應(yīng)該是不含下劃線的,簡(jiǎn)短的,小寫的名字。因?yàn)槟K名被映射到文件名,有些文件系統(tǒng)大小寫不敏感并且截短長(zhǎng)名字,模塊名被選為相當(dāng)短是重要的,這在Unix上不是問(wèn)題,但當(dāng)代碼傳到Mac或Windows上就可能是個(gè)問(wèn)題了。
當(dāng)用C或C++編寫的擴(kuò)展模塊有一個(gè)伴隨Python模塊提供高層(例如進(jìn)一步的面向?qū)ο?接口時(shí),C/C++模塊有下劃線前導(dǎo)(如:_socket)。Python包應(yīng)該是不含下劃線的,簡(jiǎn)短的,全小寫的名字。
類名
幾乎不出意料,類名使用CapWords約定。內(nèi)部使用的類外加一個(gè)前導(dǎo)下劃線。
異常名
如果模塊對(duì)所有情況定義了單個(gè)異常,它通常被叫做“error”或“Error”。似乎內(nèi)建(擴(kuò)展)的模塊使用“error”(例如:os.error),而Python模塊通常用“Error” (例如:xdrlib.Error)。趨勢(shì)似乎是傾向使用CapWords異常名。
全局變量名
(讓我們祈禱這些變量?jī)H在一個(gè)模塊的內(nèi)部有意義)
這些約定和在函數(shù)中的一樣。模塊是被設(shè)計(jì)為通過(guò)“from M import *”來(lái)使用的,必須用一個(gè)下劃線作全局變量(及內(nèi)部函數(shù)和類)的前綴防止其被導(dǎo)出(exporting)。
函數(shù)名
函數(shù)名應(yīng)該為小寫,可能用下劃線風(fēng)格單詞以增加可讀性。mixedCase僅被允許用于這種風(fēng)格已經(jīng)占優(yōu)勢(shì)的上下文(如:threading.py),以便保持向后兼容。
方法名和實(shí)例變量
這段大體上和函數(shù)相同:通常使用小寫單詞,必要時(shí)用下劃線分隔增加可讀性。僅為不打算作為類的公共界面的內(nèi)部方法和實(shí)例使用一個(gè)前導(dǎo)下劃線,Python不強(qiáng)制要求這樣:它取決于程序員是否遵守這個(gè)約定。
使用兩個(gè)前導(dǎo)下劃線以表示類私有的名字,Python將這些名字和類名連接在一起:
如果類Foo有一個(gè)屬性名為_a,它不能以Foo._a訪問(wèn)。(固執(zhí)的用戶還是可以通過(guò)Foo._Foo__a得到訪問(wèn)權(quán)。)
通常雙前導(dǎo)下劃線僅被用于避免含子類的類中的屬性名的名字沖突。
繼承的設(shè)計(jì)
始終要確定一個(gè)類中的方法和實(shí)例變量是否要被公開。通常,永遠(yuǎn)不要將數(shù)據(jù)變量公開,除非你實(shí)現(xiàn)的本質(zhì)上只是記錄,人們幾乎總是更喜歡代之給出一個(gè)函數(shù)作為類的界面(Python 2.2 的一些開發(fā)者在這點(diǎn)上做得非常漂亮)。
同樣,確定你的屬性是否應(yīng)為私有的。私有和非私有的區(qū)別在于模板將永遠(yuǎn)不會(huì)對(duì)原有的類(導(dǎo)出類)有效,而后者可以。你應(yīng)該在大腦中就用繼承設(shè)計(jì)好了你的類,私有屬性必須有兩個(gè)前導(dǎo)下劃線,無(wú)后置下劃線,非公有屬性必須有一個(gè)前導(dǎo)下劃線,無(wú)后置下劃線,公共屬性沒(méi)有前導(dǎo)和后置下劃線,除非它們與保留字沖突,在此情況下,單個(gè)后置下劃線比前置或混亂的拼寫要好,例如:class_優(yōu)于klass。
最后一點(diǎn)有些爭(zhēng)議:如果相比class_你更喜歡klass,那么這只是一致性問(wèn)題。
設(shè)計(jì)建議
單個(gè)元素(singletons)的比較,如None 應(yīng)該永遠(yuǎn)用:‘is'或‘is not'來(lái)做。當(dāng)你本意是“if x is not None”時(shí),對(duì)寫成“if x”要小心。例如當(dāng)你測(cè)試一個(gè)默認(rèn)為None的變量或參數(shù)是否被設(shè)置為其它值時(shí),這個(gè)值也許在布爾上下文(Boolean context)中是false!
基于類的異??偸呛眠^(guò)基于字符串的異常。模塊和包應(yīng)該定義它們自己的域內(nèi)特定的基異常類,基類應(yīng)該是內(nèi)建的Exception類的子類。還始終包含一個(gè)類的文檔字符串。例如:
#!Python
class MessageError(Exception):
"""Base class for errors in the email package。"""
使用字符串方法(methods)代替字符串模塊,除非必須向后兼容Python 2.0以前的版本。字符串方法總是非???,而且和unicode字符串共用同樣的API(應(yīng)用程序接口)在檢查前綴或后綴時(shí)避免對(duì)字符串進(jìn)行切片。用startswith()和endswith()代替,因?yàn)樗鼈兪敲鞔_的并且錯(cuò)誤更少。例如:
No: if foo[:3] == 'bar':
Yes: if foo。startswith('bar'):
例外是如果你的代碼必須工作在Python 1.5.2 (但是我們希望它不會(huì)發(fā)生!),對(duì)象類型的比較應(yīng)該始終用isinstance()代替直接比較類型,例如:
No: if type(obj) is type(1):
Yes: if isinstance(obj, int):
檢查一個(gè)對(duì)象是否是字符串時(shí),緊記它也可能是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,你應(yīng)該這樣做:
#!Python
from types import StringType, UnicodeType
if isinstance(obj, StringType) or \
isinstance(obj, UnicodeType) :
對(duì)序列,(字符串,列表,元組),使用空列表是false這個(gè)事實(shí),因此“if not seq”或“if seq”比“if len(seq)”或“if not len(seq)”好。書寫字符串文字時(shí)不要依賴于有意義的后置空格。這種后置空格在視覺(jué)上是不可辨別的,并且有些編輯器(特別是近來(lái),reindent.py)會(huì)將它們修整掉。不要用==來(lái)比較布爾型的值以確定是True或False(布爾型是Pythn 2.3中新增的)
No: if greeting == True:
Yes: if greeting:
No: if greeting == True:
Yes: if greeting:
這篇文檔改編自Guido最初的《Python風(fēng)格指南》一文,并從《Barry's style guide》中添加了部分內(nèi)容。在有沖突的地方,Guide的風(fēng)格規(guī)則應(yīng)該是符合本PEP的意圖(譯注:指當(dāng)有沖突時(shí),應(yīng)以Guido風(fēng)格為準(zhǔn))。這篇PEP仍然尚未完成(實(shí)際上,它可能永遠(yuǎn)都不會(huì)完成)。
在這篇風(fēng)格指導(dǎo)中的一致性是重要的。在一個(gè)項(xiàng)目?jī)?nèi)的一致性更重要。在一個(gè)模塊或函數(shù)內(nèi)的一致性最重要。但最重要的是:知道何時(shí)會(huì)不一致——有時(shí)只是沒(méi)有實(shí)施風(fēng)格指導(dǎo)。當(dāng)出現(xiàn)疑惑時(shí),運(yùn)用你的最佳判斷,看看別的例子,然后決定怎樣看起來(lái)更好。并且要不恥下問(wèn)!
打破一條既定規(guī)則的兩個(gè)好理由:
(1) 當(dāng)應(yīng)用這個(gè)規(guī)則是將導(dǎo)致代碼可讀性下降,即便對(duì)某人來(lái)說(shuō),他已經(jīng)習(xí)慣于按這條規(guī)則來(lái)閱讀代碼了。
(2) 為了和周圍的代碼保持一致而打破規(guī)則(也許是歷史原因),雖然這也是個(gè)清除其它混亂的好機(jī)會(huì)(真正的XP風(fēng)格)。
代碼的布局
縮進(jìn)
使用Emacs的Python-mode的默認(rèn)值:4個(gè)空格一個(gè)縮進(jìn)層次。對(duì)于確實(shí)古老的代碼,你不希望產(chǎn)生混亂,可以繼續(xù)使用8空格的制表符(8-space tabs)。Emacs Python-mode自動(dòng)發(fā)現(xiàn)文件中主要的縮進(jìn)層次,依此設(shè)定縮進(jìn)參數(shù)。
制表符還是空格
永遠(yuǎn)不要混用制表符和空格。最流行的Python縮進(jìn)方式是僅使用空格,其次是僅使用制表符,混合著制表符和空格縮進(jìn)的代碼將被轉(zhuǎn)換成僅使用空格。(在Emacs中,選中整個(gè)緩沖區(qū),按ESC-x去除制表符。)調(diào)用Python命令行解釋器時(shí)使用-t選項(xiàng),可對(duì)代碼中不合法得混合制表符和空格發(fā)出警告,使用-tt時(shí)警告將變成錯(cuò)誤。這些選項(xiàng)是被高度推薦的。
對(duì)于新的項(xiàng)目,強(qiáng)烈推薦僅使用空格而不是制表符。許多編輯器擁有使之易于實(shí)現(xiàn)的功能(在Emacs中,確認(rèn)indent-tabs-mode是nil)。
行的最大長(zhǎng)度
周圍仍然有許多設(shè)備被限制在每行80字符:而且,窗口限制在80個(gè)字符。使將多個(gè)窗口并排放置成為可能。在這些設(shè)備上使用默認(rèn)的折疊方式看起來(lái)有點(diǎn)丑陋。因此,請(qǐng)將所有行限制在最大79字符(Emacs準(zhǔn)確得將行限制為長(zhǎng)80字符),對(duì)順序排放的大塊文本(文檔字符串或注釋),推薦將長(zhǎng)度限制在72字符。
折疊長(zhǎng)行的首選方法是使用Pyhon支持的圓括號(hào),方括號(hào)和花括號(hào)內(nèi)的行延續(xù)。如果需要,你可以在表達(dá)式周圍增加一對(duì)額外的圓括號(hào),但是有時(shí)使用反斜杠看起來(lái)更好,確認(rèn)恰當(dāng)?shù)每s進(jìn)了延續(xù)的行。
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)
空行
用兩行空行分割頂層函數(shù)和類的定義,類內(nèi)方法的定義用單個(gè)空行分割,額外的空行可被用于(保守的)分割相關(guān)函數(shù)組成的群,在一組相關(guān)的單句中間可以省略空行。(例如:一組啞元素)。
當(dāng)空行用于分割方法的定義時(shí),在‘class'行和第一個(gè)方法定義之間也要有一個(gè)空行。在函數(shù)中使用空行時(shí),請(qǐng)謹(jǐn)慎的用于表示一個(gè)邏輯段落。Python接受contol-L(即^L)換頁(yè)符作為空格:Emacs(和一些打印工具),視這個(gè)字符為頁(yè)面分割符,因此在你的文件中,可以用他們來(lái)為相關(guān)片段分頁(yè)。
編碼
Python核心發(fā)布中的代碼必須始終使用ASCII或Latin-1編碼(又名 ISO-8859-1),使用ASCII的文件不必有編碼cookie,Latin-1僅當(dāng)注釋或文檔字符串涉及作者名字需要Latin-1時(shí)才被使用:
另外使用\x轉(zhuǎn)義字符是在字符串中包含非ASCII(non-ASCII)數(shù)據(jù)的首選方法。
作為PEP 263實(shí)現(xiàn)代碼的測(cè)試套件的部分文件是個(gè)例外。
導(dǎo)入
通常應(yīng)該在單獨(dú)的行中導(dǎo)入(Imports),例如:
No:import sys, os
Yes:import sys
import os
但是這樣也是可以的:
from types import StringType, ListType
Imports 通常被放置在文件的頂部,僅在模塊注釋和文檔字符串之后,在模塊的全局變量和常量之前。Imports應(yīng)該有順序地成組安放:
1、標(biāo)準(zhǔn)庫(kù)的導(dǎo)入(Imports )
2、相關(guān)的主包(major package)的導(dǎo)入(即,所有的email包在隨后導(dǎo)入)
3、特定應(yīng)用的導(dǎo)入(imports)
你應(yīng)該在每組導(dǎo)入之間放置一個(gè)空行,對(duì)于內(nèi)部包的導(dǎo)入是不推薦使用相對(duì)導(dǎo)入的,對(duì)所有導(dǎo)入都要使用包的絕對(duì)路徑。
從一個(gè)包含類的模塊中導(dǎo)入類時(shí),通??梢詫懗蛇@樣:
from MyClass import MyClass
from foo.bar.YourClass import YourClass
如果這樣寫導(dǎo)致了本地名字沖突,那么就這樣寫
import MyClass
import foo.bar.YourClass
即使用"MyClass.MyClass"和"foo.bar.YourClass.YourClass"
表達(dá)式和語(yǔ)句中的空格
Guido不喜歡在以下地方出現(xiàn)空格:
緊挨著圓括號(hào),方括號(hào)和花括號(hào)的,如:"spam( ham[ 1 ],{ eggs:2 } )"。要始終將它寫成"spam(ham[1],{eggs: 2})"。
緊貼在逗號(hào),分號(hào)或冒號(hào)前的,如:
"if x == 4:print x,y:x,y = y,x"。要始終將它寫成
"if x == 4:print x,y:x,y = y,x"。
緊貼著函數(shù)調(diào)用的參數(shù)列表前開式括號(hào)(open parenthesis )的,如"spam (1)"。要始終將它寫成"spam(1)"。
緊貼在索引或切片,開始的開式括號(hào)前的,如:
"dict ['key'] = list [index]"。要始終將它寫成"dict['key'] = list[index]"。
在賦值(或其它)運(yùn)算符周圍的用于和其它并排的一個(gè)以上的空格,如:
#!Python
x= 1
y= 2
long_variable = 3
要始終將它寫成
#!Python
x = 1
y = 2
long_variable = 3
(不要對(duì)以上任意一條和他爭(zhēng)論——Guido 養(yǎng)成這樣的風(fēng)格超過(guò)20年了。)
其它建議
始終在這些二元運(yùn)算符兩邊放置一個(gè)空格:賦值(=), 比較(==,<,>,!=,<>,<=, >=,in,not in,is,is not),布爾運(yùn)算 (and,or,not)。
按你的看法在算術(shù)運(yùn)算符周圍插入空格。 始終保持二元運(yùn)算符兩邊空格的一致。
一些例子:
#!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)
不要在用于指定關(guān)鍵字參數(shù)或默認(rèn)參數(shù)值的'='號(hào)周圍使用空格,例如:
#!Python
def complex(real, imag=0。0):
return magic(r=real, i=imag)
不要將多條語(yǔ)句寫在同一行上:
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()
注釋
同代碼不一致的注釋比沒(méi)注釋更差。當(dāng)代碼修改時(shí),始終優(yōu)先更新注釋!注釋應(yīng)該是完整的句子,如果注釋是一個(gè)短語(yǔ)或句子,首字母應(yīng)該大寫,除非他是一個(gè)以小寫字母開頭的標(biāo)識(shí)符(永遠(yuǎn)不要修改標(biāo)識(shí)符的大小寫)。
如果注釋很短,最好省略末尾的句號(hào)。注釋塊通常由一個(gè)或多個(gè)由完整句子構(gòu)成的段落組成,每個(gè)句子應(yīng)該以句號(hào)結(jié)尾。你應(yīng)該在句末,句號(hào)后使用兩個(gè)空格,以便使Emacs的斷行和填充工作協(xié)調(diào)一致。
用英語(yǔ)書寫時(shí),斷詞和空格是可用的。非英語(yǔ)國(guó)家的Python程序員:請(qǐng)用英語(yǔ)書寫你的注釋,除非你120%的確信這些代碼不會(huì)被不懂你的語(yǔ)言的人閱讀。
注釋塊
注釋塊通常應(yīng)用于跟隨著一些(或者全部)代碼并和這些代碼有著相同的縮進(jìn)層次。注釋塊中每行以‘#'和一個(gè)空格開始(除非他是注釋內(nèi)的縮進(jìn)文本)。注釋塊內(nèi)的段落以僅含單個(gè)‘#'的行分割。注釋塊上下方最好有一空行包圍(或上方兩行下方一行,對(duì)一個(gè)新函數(shù)定義段的注釋)。
行內(nèi)注釋
一個(gè)行內(nèi)注釋是和語(yǔ)句在同一行的注釋,行內(nèi)注釋應(yīng)該謹(jǐn)慎適用,行內(nèi)注釋應(yīng)該至少用兩個(gè)空格和語(yǔ)句分開,它們應(yīng)該以'#'和單個(gè)空格開始。
x = x+1 # Increment x
如果語(yǔ)意是很明了的,那么行內(nèi)注釋是不必要的,事實(shí)上是應(yīng)該被移除的。不要這樣寫:
x = x+1 # Increment x
x = x+1 # Compensate for border
但是有時(shí),這樣是有益的:
x = x+1 # Compensate for border
文檔字符串
應(yīng)該一直遵守編寫好的文檔字符串的約定PEP 257 [3]。為所有公共模塊,函數(shù),類和方法編寫文檔字符串。文檔字符串對(duì)非公開的方法不是必要的,但你應(yīng)該有一個(gè)描述這個(gè)方法做什么的注釋。這個(gè)注釋應(yīng)該在"def"這行后。
PEP 257 描述了好的文檔字符串的約定。一定注意,多行文檔字符串結(jié)尾的"""應(yīng)該單獨(dú)成行,例如:
"""Return a foobang
Optional plotz says to frobnicate the bizbaz first。
"""
對(duì)單行的文檔字符串,結(jié)尾的"""在同一行也可以。
版本注記
如果你要將RCS或CVS的雜項(xiàng)(crud)包含在你的源文件中,按如下做。
#!Python
__version__ = "$Revision: 1。4 $"
# $Source: E:/cvsroot/Python_doc/pep8。txt,v $
這個(gè)行應(yīng)該包含在模塊的文檔字符串之后,所有代碼之前,上下用一個(gè)空行分割。
命名約定
Python庫(kù)的命名約定有點(diǎn)混亂,所以我們將永遠(yuǎn)不能使之變得完全一致,不過(guò)還是有公認(rèn)的命名規(guī)范的。新的模塊和包(包括第三方的框架)必須符合這些標(biāo)準(zhǔn),但對(duì)已有的庫(kù)存在不同風(fēng)格的,保持內(nèi)部的一致性是首選的。
描述:命名風(fēng)格
有許多不同的命名風(fēng)格。以下的有助于辨認(rèn)正在使用的命名風(fēng)格,獨(dú)立于它們的作用。 以下的命名風(fēng)格是眾所周知的:
b (單個(gè)小寫字母)
B (單個(gè)大寫字母)
Lowercase(小寫)
lower_case_with_underscores(有下劃線的小寫)
UPPERCASE(大寫)
UPPER_CASE_WITH_UNDERSCORES(有下劃線的大寫)
CapitalizedWords (或 CapWords,CamelCase這樣命名是因?yàn)榭蓮淖帜傅拇笮懛殖鰡卧~。這有時(shí)也被當(dāng)作StudlyCaps。
mixedCase (與CapitalizedWords的不同在于首字母小寫!)
Capitalized_Words_With_Underscores(有下劃線的首字母大寫) (丑陋!)
還有用短的特別前綴將相關(guān)的名字聚合在一起的風(fēng)格。這在Python中不常用,但是出于完整性要提一下,例如,os.stat()函數(shù)返回一個(gè)元組,他的元素傳統(tǒng)上說(shuō)名如st_mode, st_size,st_mtime等等。
X11庫(kù)的所有公開函數(shù)以X開頭。(在Python中,這個(gè)風(fēng)格通常認(rèn)為是不必要的,因?yàn)閷傩院头椒詫?duì)象作前綴,而函數(shù)名以模塊名作前綴。)
另外,以下用下劃線作前導(dǎo)或結(jié)尾的特殊形式是被公認(rèn)的(這些通常可以和任何習(xí)慣組合):
_single_leading_underscore(單個(gè)下劃線作前導(dǎo)):弱的“內(nèi)部使用(internal use)”標(biāo)志。 (例如,“from M import *”不會(huì)導(dǎo)入以下劃線開頭的對(duì)象)。
single_trailing_underscore_(單個(gè)下劃線結(jié)尾): 用于避免與Python關(guān)鍵詞的沖突,例如:“Tkinter.Toplevel(master,class_='ClassName')”。
_double_leading_underscore(雙下劃線):從Python 1.4起為類私有名。
_double_leading_and_trailing_underscore_:“magic”對(duì)象或?qū)傩?,存在于用戶控制?user-controlled)名字空間,例如:_init_, _import_ 或_file_。有時(shí)它們被用戶定義用于觸發(fā)某個(gè)魔法行為(例如:運(yùn)算符重載):有時(shí)被構(gòu)造器插入,以便自己使用或?yàn)榱苏{(diào)試。因此,在未來(lái)的版本中,構(gòu)造器(松散得定義為Python解釋器和標(biāo)準(zhǔn)庫(kù))可能打算建立自己的魔法屬性列表,用戶代碼通常應(yīng)該限制將這種約定作為己用。欲成為構(gòu)造器的一部分的用戶代碼可以在下滑線中結(jié)合使用短前綴,例如:
_bobo_magic_attr__。
說(shuō)明:命名約定
應(yīng)避免的名字。永遠(yuǎn)不要用字符‘l'(小寫字母el(就是讀音,下同)),‘O'(大寫字母oh),或‘I'(大寫字母eye)作為單字符的變量名。在某些字體中這些字符不能與數(shù)字1和0分辨。試著在使用‘l'時(shí)用‘L'代替。
模塊名
模塊應(yīng)該是不含下劃線的,簡(jiǎn)短的,小寫的名字。因?yàn)槟K名被映射到文件名,有些文件系統(tǒng)大小寫不敏感并且截短長(zhǎng)名字,模塊名被選為相當(dāng)短是重要的,這在Unix上不是問(wèn)題,但當(dāng)代碼傳到Mac或Windows上就可能是個(gè)問(wèn)題了。
當(dāng)用C或C++編寫的擴(kuò)展模塊有一個(gè)伴隨Python模塊提供高層(例如進(jìn)一步的面向?qū)ο?接口時(shí),C/C++模塊有下劃線前導(dǎo)(如:_socket)。Python包應(yīng)該是不含下劃線的,簡(jiǎn)短的,全小寫的名字。
類名
幾乎不出意料,類名使用CapWords約定。內(nèi)部使用的類外加一個(gè)前導(dǎo)下劃線。
異常名
如果模塊對(duì)所有情況定義了單個(gè)異常,它通常被叫做“error”或“Error”。似乎內(nèi)建(擴(kuò)展)的模塊使用“error”(例如:os.error),而Python模塊通常用“Error” (例如:xdrlib.Error)。趨勢(shì)似乎是傾向使用CapWords異常名。
全局變量名
(讓我們祈禱這些變量?jī)H在一個(gè)模塊的內(nèi)部有意義)
這些約定和在函數(shù)中的一樣。模塊是被設(shè)計(jì)為通過(guò)“from M import *”來(lái)使用的,必須用一個(gè)下劃線作全局變量(及內(nèi)部函數(shù)和類)的前綴防止其被導(dǎo)出(exporting)。
函數(shù)名
函數(shù)名應(yīng)該為小寫,可能用下劃線風(fēng)格單詞以增加可讀性。mixedCase僅被允許用于這種風(fēng)格已經(jīng)占優(yōu)勢(shì)的上下文(如:threading.py),以便保持向后兼容。
方法名和實(shí)例變量
這段大體上和函數(shù)相同:通常使用小寫單詞,必要時(shí)用下劃線分隔增加可讀性。僅為不打算作為類的公共界面的內(nèi)部方法和實(shí)例使用一個(gè)前導(dǎo)下劃線,Python不強(qiáng)制要求這樣:它取決于程序員是否遵守這個(gè)約定。
使用兩個(gè)前導(dǎo)下劃線以表示類私有的名字,Python將這些名字和類名連接在一起:
如果類Foo有一個(gè)屬性名為_a,它不能以Foo._a訪問(wèn)。(固執(zhí)的用戶還是可以通過(guò)Foo._Foo__a得到訪問(wèn)權(quán)。)
通常雙前導(dǎo)下劃線僅被用于避免含子類的類中的屬性名的名字沖突。
繼承的設(shè)計(jì)
始終要確定一個(gè)類中的方法和實(shí)例變量是否要被公開。通常,永遠(yuǎn)不要將數(shù)據(jù)變量公開,除非你實(shí)現(xiàn)的本質(zhì)上只是記錄,人們幾乎總是更喜歡代之給出一個(gè)函數(shù)作為類的界面(Python 2.2 的一些開發(fā)者在這點(diǎn)上做得非常漂亮)。
同樣,確定你的屬性是否應(yīng)為私有的。私有和非私有的區(qū)別在于模板將永遠(yuǎn)不會(huì)對(duì)原有的類(導(dǎo)出類)有效,而后者可以。你應(yīng)該在大腦中就用繼承設(shè)計(jì)好了你的類,私有屬性必須有兩個(gè)前導(dǎo)下劃線,無(wú)后置下劃線,非公有屬性必須有一個(gè)前導(dǎo)下劃線,無(wú)后置下劃線,公共屬性沒(méi)有前導(dǎo)和后置下劃線,除非它們與保留字沖突,在此情況下,單個(gè)后置下劃線比前置或混亂的拼寫要好,例如:class_優(yōu)于klass。
最后一點(diǎn)有些爭(zhēng)議:如果相比class_你更喜歡klass,那么這只是一致性問(wèn)題。
設(shè)計(jì)建議
單個(gè)元素(singletons)的比較,如None 應(yīng)該永遠(yuǎn)用:‘is'或‘is not'來(lái)做。當(dāng)你本意是“if x is not None”時(shí),對(duì)寫成“if x”要小心。例如當(dāng)你測(cè)試一個(gè)默認(rèn)為None的變量或參數(shù)是否被設(shè)置為其它值時(shí),這個(gè)值也許在布爾上下文(Boolean context)中是false!
基于類的異??偸呛眠^(guò)基于字符串的異常。模塊和包應(yīng)該定義它們自己的域內(nèi)特定的基異常類,基類應(yīng)該是內(nèi)建的Exception類的子類。還始終包含一個(gè)類的文檔字符串。例如:
#!Python
class MessageError(Exception):
"""Base class for errors in the email package。"""
使用字符串方法(methods)代替字符串模塊,除非必須向后兼容Python 2.0以前的版本。字符串方法總是非???,而且和unicode字符串共用同樣的API(應(yīng)用程序接口)在檢查前綴或后綴時(shí)避免對(duì)字符串進(jìn)行切片。用startswith()和endswith()代替,因?yàn)樗鼈兪敲鞔_的并且錯(cuò)誤更少。例如:
No: if foo[:3] == 'bar':
Yes: if foo。startswith('bar'):
例外是如果你的代碼必須工作在Python 1.5.2 (但是我們希望它不會(huì)發(fā)生!),對(duì)象類型的比較應(yīng)該始終用isinstance()代替直接比較類型,例如:
No: if type(obj) is type(1):
Yes: if isinstance(obj, int):
檢查一個(gè)對(duì)象是否是字符串時(shí),緊記它也可能是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,你應(yīng)該這樣做:
#!Python
from types import StringType, UnicodeType
if isinstance(obj, StringType) or \
isinstance(obj, UnicodeType) :
對(duì)序列,(字符串,列表,元組),使用空列表是false這個(gè)事實(shí),因此“if not seq”或“if seq”比“if len(seq)”或“if not len(seq)”好。書寫字符串文字時(shí)不要依賴于有意義的后置空格。這種后置空格在視覺(jué)上是不可辨別的,并且有些編輯器(特別是近來(lái),reindent.py)會(huì)將它們修整掉。不要用==來(lái)比較布爾型的值以確定是True或False(布爾型是Pythn 2.3中新增的)
No: if greeting == True:
Yes: if greeting:
No: if greeting == True:
Yes: if greeting:
相關(guān)文章
python實(shí)現(xiàn)合并兩個(gè)數(shù)組的方法
這篇文章主要介紹了python實(shí)現(xiàn)合并兩個(gè)數(shù)組的方法,實(shí)例分析了兩種常用的合并數(shù)組的技巧,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2015-05-05解決出現(xiàn)Incorrect integer value: '''' for column ''id'' at row 1
這篇文章主要介紹了解決出現(xiàn)Incorrect integer value: '' for column 'id' at row 1的問(wèn)題的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家遇到這樣的問(wèn)題及時(shí)的解決,需要的朋友可以參考下2017-10-10如何使用python爬取B站排行榜Top100的視頻數(shù)據(jù)
本文章向大家介紹python爬取b站排行榜,包括python爬取b站排行榜的具體代碼,對(duì)大家的學(xué)習(xí)或工作具有一定的參考價(jià)值,需要的朋友可以參考一下2021-09-09Python 檢查數(shù)組元素是否存在類似PHP isset()方法
isset方法來(lái)檢查數(shù)組元素是否存在,在Python中無(wú)對(duì)應(yīng)函數(shù),在Python中一般可以通過(guò)異常來(lái)處理數(shù)組元素不存在的情況,而無(wú)須事先檢查2014-10-10PyTorch 遷移學(xué)習(xí)實(shí)戰(zhàn)
本文主要介紹了PyTorch 遷移學(xué)習(xí)實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01Python3+Pygame實(shí)現(xiàn)射擊游戲完整代碼
這篇文章主要介紹了Python3+Pygame實(shí)現(xiàn)射擊游戲完整代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03選擇python進(jìn)行數(shù)據(jù)分析的理由和優(yōu)勢(shì)
在本篇文章中小編給大家整理了關(guān)于選擇python進(jìn)行數(shù)據(jù)分析的理由和優(yōu)勢(shì),對(duì)此有需要的朋友們可以跟著學(xué)習(xí)參考下。2019-06-06