Python開發編碼規範

NO IMAGE
1 Star2 Stars3 Stars4 Stars5 Stars 給文章打分!
Loading...

這篇文件所給出的編碼約定適用於在主要的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:

您可能感興趣的文章:

python 編碼規範整理Python 常用 PEP8 編碼規範詳解Python 編碼規範(Google Python Style Guide)

程式語言 最新文章