Python Coding Rule

介紹

  • 這篇文檔所給出的編碼約定適用於在主要的Python發佈版本中組成標準庫的Python 代碼.請查閱相關的關於在Python的C實現中C代碼風格指南的描述. 這篇文檔改編自Guido最初的《Python風格指南》一文. 並從《Barry's style guide》中添加了部份內容. 在有衝突的地方,Guide的風格規則應該是符合本PEP的意圖 (譯註:就是當有衝突時,應以Guido風格爲準) 這篇PEP也許仍然還沒有完成(實際上,它可能永遠不會結束).

一致性的建議

愚蠢得使用一致性是無知的妖怪(A Foolish Consistency is the Hobgoblin of Little Minds)html

呆板的堅持一致性是傻的沒邊了!-- Zoomq
  • 在這篇風格指導中的一致性是重要的. 在一個項目內的一致性更重要. 在一個模塊或函數內的一致性最重要. 但最重要的是:知道什麼時候會不一致 -- 有時只是沒有實施風格指導.當出現疑惑時,
    • 運用你的最佳判斷.看看別的例子,而後決定怎樣看起來更好.而且要不恥下問!
  • 打破一條既定規則的兩個好理由:
    1. 當應用這個規則是將致使代碼可讀性降低,即使對某人來講,他已經習慣於按這條規則來閱讀代碼了.
    2. 爲了和周圍的代碼保持一致而打破規則(也許是歷史緣由)
      • -- 雖然這也是個清除其它混亂的好機會(真正的XP風格).

代碼的佈局

(Code lay-out)python

縮進

(Indentation)程序員

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

製表符仍是空格?

(Tabs or Spaces)api

  • 永遠不要混用製表符和空格. 最流行的Python縮進方式是僅使用空格, 其次是僅使用製表符.混合着製表符和空格縮進的代碼將被轉換成僅使用空格. (在Emacs中,選中整個緩衝區,按ESC-x去除製表符(untabify).) 調用python命令行解釋器時使用-t選項,可對代碼中不合法得混合製表符和空格發出警告(warnings). 使用-tt時警告(warnings)將變成錯誤(errors).這些選項是被高度推薦的. 對於新的項目,強烈推薦僅使用空格(spaces-only)而不是製表符. 許多編輯器擁有使之易於實現的功能.(在Emacs中,確認indent-tabs-mode是nil).

行的最大長度

(Maximum Line Length)服務器

  • 周圍仍然有許多設備被限制在每行80字符;並且,窗口限制在80個字符 使將多個窗口並排放置成爲可能.在這些設備上使用默認的摺疊(wrapping)方式看起來有點醜陋. 所以,請將全部行限制在最大79字符(Emacs準確得將行限制爲長80字符), 對順序排放的大塊文本(文檔字符串或註釋),推薦將長度限制在72字符. 摺疊長行的首選方法是使用Pyhon支持的圓括號,方括號(brackets)和花括號(braces)內的行延續. 若是須要,你能夠在表達式周圍增長一對額外的圓括號, 可是有時使用反斜槓看起來更好.確認恰當得縮進了延續的行. Emacs的Python-mode正確得完成了這些.一些例子:

Toggle line numbers
 1  class Rectangle(Blob):  2  def __init__(self, width, height,  3  color='black', emphasis=None, highlight=0):  4  if width == 0 and height == 0 and \  5  color == 'red' and emphasis == 'strong' or \  6  highlight > 100:  7  raise ValueError, "sorry, you lose"  8  if width == 0 and height == 0 and (color == 'red' or  9  emphasis is None):  10  raise ValueError, "I don't think so"  11  Blob.__init__(self, width, height,  12  color, emphasis, highlight)

空行

(Blank Lines)cookie

  • 用兩行空行分割頂層函數和類的定義,類內方法的定義用單個空行分割.
  • 額外的空行可被用於(保守的(sparingly))分割一組相關函數(groups of related functions). 在一組相關的單句中間能夠省略空行.(例如.一組啞元(a set of dummy implementations)).
  • 當空行用於分割方法(method)的定義時,在'class'行和第一個方法定義之間也要有一個空行.
  • 在函數中使用空行時,請謹慎的用於表示一個邏輯段落(indicate logical sections). Python接受contol-L(即^L)換頁符做爲空格;Emacs(和一些打印工具) 視這個字符爲頁面分割符,所以在你的文件中,能夠用他們來爲相關片斷(sections)分頁.

編碼

(Encodings)(PEP 263)app

  • Python核心發佈中的代碼必須始終使用ASCII或Latin-1編碼(又名 ISO-8859-1). 使用ASCII的文件沒必要有譯碼cookie(coding cookie). Latin-1僅當註釋或文檔字符串涉及做者名字須要Latin-1時才被使用; 另外使用\x轉義字符是在字符串中包含非ASCII(non-ASCII)數據的首選方法. 做爲PEP 263實現代碼的測試套件的部分文件是個例外.

Python 2.4 之後內核支持 Unicode 了!不論什麼狀況使用 UTF-8 吧!這是王道!

--ZoomQuiet框架

導入

(Imports)socket

  • 一般應該在單獨的行中導入(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"編輯器

空格

(Whitespace in Expressions and Statements)

  • Guido不喜歡在如下地方出現空格:
  • "spam( ham[ 1 ], { eggs: 2 } )".  Always write this as "spam(ham[1], {eggs: 2})".

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

    "if x == 4 : print x , y ; x , y = y , x". Always write this as "if x == 4: print x, y; x, y = y, x".

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

    "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)".

    slicing, as in: "dict ['key'] = list [index]". Always write this as "dict['key'] = list[index]".

    • 緊貼在索引或切片(slicing?下標?)開始的開式括號前的,如:

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

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

Toggle line numbers
 1  x = 1  2  y = 2  3  long_variable = 3
  • 要始終將它寫成

Toggle line numbers
 1  x = 1  2  y = 2  3  long_variable = 3
  • (不要對以上任意一條和他爭論 --- Guido 養成這樣的風格超過20年了.)

其它建議

(Other Recommendations)

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

* 按你的見解在算術運算符周圍插入空格. 始終保持二元運算符兩邊空格的一致.

  • 一些例子:

Toggle line numbers
 1  i = i+1  2  submitted = submitted + 1  3  x = x*2 - 1  4  hypot2 = x*x + y*y  5  c = (a+b) * (a-b)  6  c = (a + b) * (a - b)
  • 不要在用於指定關鍵字參數或默認參數值的'='號周圍使用空格,例如:

Toggle line numbers
 1  def complex(real, imag=0.0):  2  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()

註釋

(Comments)

  • 同代碼不一致的註釋比沒註釋更差.當代碼修改時,始終優先更新註釋! 註釋應該是完整的句子. 若是註釋是一個短語或句子,首字母應該大寫, 除非他是一個以小寫字母開頭的標識符(永遠不要修改標識符的大小寫). 若是註釋很短,最好省略末尾的句號(period?結尾句末的停頓?也能夠是逗號吧,) 註釋塊一般由一個或多個由完整句子構成的段落組成,每一個句子應該以句號結尾. 你應該在句末,句號後使用兩個空格,以便使Emacs的斷行和填充工做協調一致 (譯按:應該說是使這兩種功能正常工做,". "給出了文檔結構的提示). 用英語書寫時,斷詞和空格是可用的. 非英語國家的Python程序員:請用英語書寫你的註釋,除非你120%的確信 這些代碼不會被不懂你的語言的人閱讀.

我就是堅持所有使用中文來註釋,真正要發佈腳本工具時,再想E文的;開發時每一瞬間都要用在思量中,堅定不用在E文語法,單詞的回憶中!

-- ZoomQUiet

  • 約定使用統一的文檔化註釋格式有利於良好習慣和團隊建議!-- CodeCommentingRule

註釋塊

(Block Comments)

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

行內註釋

(Inline Comments)

  • (inline?內聯?翻成"行內"比較好吧)
    • 一個行內註釋是和語句在同一行的註釋.行內註釋應該謹慎適用. 行內註釋應該至少用兩個空格和語句分開. 它們應該以'#'和單個空格開始.

x = x+1                 # Increment x
  • 若是語意是很明瞭的,那麼行內註釋是沒必要要的,事實上是應該被去掉的. 不要這樣寫:

x = x+1                 # Increment x

x = x+1                 # Compensate for border
  • 可是有時,這樣是有益的:

x = x+1                 # Compensate for border

文檔化

(Documentation Strings)

  • Conventions for writing good documentation strings (a.k.a. "docstrings") are immortalized in

    PEP 257. 應該一直遵照編寫好的文檔字符串(又名"docstrings")的約定(?實在不知道怎麼譯)

Documentation Strings-- 文檔化字符 ;爲配合 pydoc;epydoc,Doxygen等等文檔化工具的使用,相似於MoinMoin 語法,約定一些字符,以便自動提取轉化爲有意義的文檔章節等等文章元素!-- Zoomq
  • 爲全部公共模塊,函數,類和方法編寫文檔字符串.文檔字符串對非公開的方法不是必要的,但你應該有一個描述這個方法作什麼的註釋.這個註釋應該在"def"這行後.
  • PEP 257 描述了好的文檔字符串的約定.必定注意,多行文檔字符串結尾的""" 應該單獨成行,例如:

"""Return a foobang          Optional plotz says to frobnicate the bizbaz first.          """
  • 對單行的文檔字符串,結尾的"""在同一行也能夠.

實際上Python 自個兒就使用文檔化編碼維護着全部內置對象的使用說明\不信的話常試:        #python>>> import time>>> dir(time)['__doc__', '__file__', '__name__', 'accept2dyear', 'altzone', 'asctime', 'clock', 'ctime', 'daylight', 'gmtime', 'localtime', 'mktime', 'sleep', 'strftime', 'strptime', 'struct_time', 'time', 'timezone', 'tzname', 'tzset']>>> help(time.time)Help on built-in function time in module time:time(...)        time() -> floating point number        Return the current time in seconds since the Epoch.        Fractions of a second may be present if the system clock provides them.

版本註記

(Version Bookkeeping) (我以爲叫"註記"更好)

  • 若是你要將RCS或CVS的雜項(crud)包含在你的源文件中,按以下作.

Toggle line numbers
 1  __version__ = "$Revision: 1.4 $"  2  # $Source: E:/cvsroot/python_doc/pep8.txt,v $
  • 這個行應該包含在模塊的文檔字符串以後,全部代碼以前,上下用一個空行分割.

對於CVS的服務器工做標記更應該在代碼段中明確出它的使用如:在文檔的最開始的版權聲明後應加入以下版本標記:# 文件:$id$# 版本: $Revision$這樣的標記在提交給配置管理服務器後,會自動適配成爲相應的字符串,如:# 文件:$Id: ussp.py,v 1.22 2004/07/21 04:47:41 hd Exp $# 版本: $Revision: 1.4 $----HD

命名約定

(Naming Conventions)

  • Python庫的命名約定有點混亂,因此咱們將永遠不能使之變得徹底一致--- 不過仍是有公認的命名規範的. 新的模塊和包(包括第三方的框架)必須符合這些標準,但對已有的庫存在不一樣風格的, 保持內部的一致性是首選的.

描述:命名風格

(Descriptive: Naming Styles)

  • 有許多不一樣的命名風格.如下的有助於辨認正在使用的命名風格,獨立於它們的做用. 如下的命名風格是衆所周知的:
  • b (單個小寫字母)
  • B (單個大寫字母)
  • 小寫串 如:getname
  • 帶下劃的小寫串 如:_getname
  • 大寫串 如:GETNAME
  • 帶下劃的大寫串 如:_GETNAME
  • CapitalizedWords(首字母大寫單詞串) (或 CapWords, CamelCase -- 這樣命名是因爲它的字母錯落有致的樣子而來的.

    • 這有時也被看成StudlyCaps. 如:GetName

  • mixedCase (混合大小寫串)(與首字母大寫串不一樣之處在於第一個字符是小寫如:getName)

  • Capitalized_Words_With_Underscores(帶下劃線的首字母大寫串) (醜陋!)

  • 還有一種使用特別前綴的風格,用於將相關的名字分紅組.這在Python中不經常使用,
  • 可是出於完整性要提一下.例如,
    os.stat()函數返回一個tuple, 他的元素傳統上有象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__. 有時它們被用戶定義, 用於觸發某個特殊行爲(magic behavior)(例如:運算符重載); 有時被構造器(infrastructure)插入,以便本身使用或爲了調試. 所以,在將來的版本中,構造器(鬆散得定義爲Python解釋器和標準庫) 可能打算創建本身的魔法屬性列表,用戶代碼一般應該限制將這種約定做爲己用. 欲成爲構造器的一部分的用戶代碼能夠在下滑線中結合使用短前綴,例如. __bobo_magic_attr__.

說明:命名約定

(Prescriptive: Naming Conventions)

應避免的名字

(Names to Avoid)

  • 永遠不要用字符`l'(小寫字母el(就是讀音,下同)),

    O'(大寫字母oh),或I'(大寫字母eye)做爲單字符的變量名. 在某些字體中,這些字符不能與數字1和0分開.當想要使用'l'時,用'L'代替它.

模塊名

(Module Names)

  • 模塊應該是不含下劃線的,簡短的,小寫的名字. 由於模塊名被映射到文件名, 有些文件系統大小寫不敏感而且截短長名字, 模塊名被選爲至關短是重要的---這在Unix上不是問題, 但當代碼傳到Mac 或Windows上就多是個問題了. 當一個用C或C++寫的擴展模塊有一個伴隨的Python模塊,這個Python模塊提供了
    • 一個更高層(例如,更面向對象)的接口時,C/C++模塊有一個前導下劃線(如:_socket)
    Python包應該是不含下劃線的,簡短的,全小寫的名字.

類名

(Class Names)

  • 幾乎沒有例外,類名老是使用首字母大寫單詞串(CapWords)的約定.

異常名

(Exception Names)

  • 若是模塊對全部狀況定義了單個異常,它一般被叫作"error"或"Error". 彷佛內建(擴展)的模塊使用"error"(例如:os.error), 而Python模塊一般用"Error" (例如: xdrlib.Error).

    趨勢彷佛是傾向使用CapWords異常名.

全局變量名

(Global Variable Names)

  • (讓咱們但願這些變量打算只被用於模塊內部) 這些約定與那些用於函數的約定差很少.被設計能夠經過"from M import *"來使用的
    • 那些模塊,應該在那些不想被導入的全局變量(還有內部函數和類)前加一個下劃線).

函數名

(Function Names)

  • 函數名應該爲小寫,可能用下劃線風格單詞以增長可讀性.

    mixedCase僅被容許用於這種風格已經佔優點的上下文(如: threading.py) 以便保持向後兼容.

方法名和實例變量

(Method Names and Instance Variables)

  • 這段大致上和函數相同:一般使用小寫單詞,必要時用下劃線分隔增長可讀性. 使用一個前導下劃線僅用於不打算做爲類的公共接口的內部方法和實例變量. Python不強制要求這樣; 它取決於程序員是否遵照這個約定. 使用兩個前導下劃線以表示類私有的名字. Python將這些名字和類名鏈接在一塊兒:

    若是類Foo有一個屬性名爲 __a, 它不能以Foo.__a訪問. (執著的用戶(An insistent user)仍是能夠經過Foo._Foo__a獲得訪問權.) 一般,雙前導下劃線應該只用來避免與類(爲能夠子類化所設計)中的屬性發生名字衝突.

繼承的設計

(Designing for inheritance)

  • 始終要肯定一個類中的方法和實例變量是否要被公開. 一般,永遠不要將數據變量公開,除非你實現的本質上只是記錄. 人們老是更喜歡給類提供一個函數的接口做爲替換 (Python 2.2 的一些開發者在這點上作得很是漂亮). 一樣,肯定你的屬性是否應爲私有的.私有與非公有的區別在於: 前者永遠不會被用在一個派生類中,然後者可能會. 是的,你應該在大腦中就用繼承設計好了你的類. 私有屬性必須有兩個前導下劃線,無後置下劃線. 非公有屬性必須有一個前導下劃線,無後置下劃線. 公共屬性沒有前導和後置下劃線,除非它們與保留字衝突, 在此狀況下,單個後置下劃線比前置或混亂的拼寫要好, 例如:class_優於klass. 最後一點有些爭議; 若是相比class_你更喜歡klass,那麼這只是一致性問題.

設計建議

(Programming Recommendations)

  • 同象None之類的單值進行比較,應該永遠用:'is'或'is not'來作. 當你本意是"if x is not None"時,對寫成"if x"要當心 -- 例如當你測試一個默認爲None的變量或參數是否被設置爲其它值時. 這個其它值多是一個在布爾上下文中爲假的值!
  • 基於類的異常老是好過基於字符串的異常. 模塊和包應該定義它們本身的域內特定的基異常類(base exception class), 基類應該是內建的Exception類的子類. 還始終包含一個類的文檔字符串.例如:

Toggle line numbers
 1  class MessageError(Exception):  2  """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,因此你能夠這樣作:

Toggle line numbers
 1  if isinstance(obj, basestring):
  • 在Python 2.2 類型模塊爲此定義了StringTypes類型, 例如:

Toggle line numbers
 1  from types import StringTypes  2  if isinstance(obj, StringTypes):
  • 在Python 2.0和2.1,你應該這樣作:

Toggle line numbers
 1  from types import StringType, UnicodeType  2  if isinstance(obj, StringType) or \  3  isinstance(obj, UnicodeType) :
  • 對序列,(字符串(strings),列表(lists),元組(tuples)), 使用空列表是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:
相關文章
相關標籤/搜索