◎ 本文轉載自 https://wiki.jiayun.org/PEP_8_--_Style_Guide_for_Python_Code#References,原作者為 Guido van Rossum、Barry Warsaw,翻譯者為:JiaYun
本文件提供 Python 主要發行版本標準程式庫中的 Python 程式碼所用的撰寫慣例。關於 Python 的 C 實作中所用的 C 語言風格指引,請參考相關的 PEP[1]。
本文件改寫自 Guido 所寫的 Python 風格指引文章 [2],並增添一些 Barry 的風格指引 [5] 的內容。當兩者有衝突時,本 PEP 以 Guido 風格為準。本 PEP 可能仍未完成(事實上,可能永遠不會完工<眨眼>)。
Guido 的重要見解之一是:程式碼被閱讀的次數,遠大於被撰寫的次數。提供本指引的目的,是為了增進程式碼的可讀性,並使 Python 程式碼在各方面保持一致性。如同 PEP 20 [6] 所說的「可讀性至關重要」。
風格指引關注的是一致性。和本指引一致很重要,在專案中保持一致性又更重要,但在 module 或 function 中保持一致性則最重要。
但更更重要的是:知道何時該不一致 -- 有時候風格指引就是無法適用。有疑惑時,運用你的最佳判斷力。看看其他例子,並決定何者最好看。需要的時候,儘管發問。
打破特定規則的兩個好理由:
縮排
每個縮排層級使用 4 個空白。
在相當舊的程式碼中,為了一致可以繼續使用 tab。
tab 或空白?
絕對不要混用 tab 和空白。
縮排 Python 最常用的方式是只用空白。第二常用的方式是只用 tab。混用 tab 和空白來縮排的程式碼,應該轉成只用空白。在呼叫 Python 直譯器時加上 -t 選項,它會對混用 tab 和空白的程式發出警告。若使用 -tt 選項,則發出的會是錯誤。非常推薦使用這些選項!
對於新專案來說,只用空白比用 tab 更受推薦。大多數編輯器都有相關設定,可以很容易做到這點。
每行最大長度
將每一行限制在最多 79 個字元之內。
仍然有很多裝置受限於每行 80 個字元;而且視窗寬度限制在 80 個字元內,可以方便讓多個視窗並排。這些裝置的預設斷行機制會破壞程式碼的顯示結構,而使程式碼更難理解。所以,請將每一行限制在最多 79 個字元之內。對於大區段的文字(docstring 或註解),建議每行限制在 72 個字元內。
建議的斷行方式是運用圓括號、方括號、大括號在 Python 中隱含的行接續作用。若需要,也可以對 expression 增加額外的圓括號,但有時只用反斜線看起來會更好。確保接續的行有妥善縮排。一些例子:
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)
空白行
將最高層級的 function 和 class 定義以兩個空白行分隔。
class 內的 method 定義之間以一個空白行分隔。
額外的空白行可以(謹慎地)用於分隔不同群組的相關 function。在一群相關的單行程式碼中(例如一組空的實作),空白行可以省略。
在 function 中,小心地使用空白行來表示邏輯上的分段。
Python 將 control-L(也就是 ^L)換頁字元視為空白。很多工具將這字元用於表示換頁,所以在你的檔案中,可以用它來為各相關區段作分頁。
編碼 (PEP 263)
Python 核心發行版本中的程式碼應該都使用 ASCII 或 Latin-1(即 ISO-8859-1)編碼。對於 Python 3.0 或以上版本,UTF-8 比 Latin-1 更建議使用,參考 PEP 3120。
使用 ASCII(或 UTF-8,在 Python 3.0 時)的程式檔案不該使用編碼指示(像是 "coding: utf-8")。Latin-1(或 UTF-8)應該只用在註解或 docstring 提到作者的名字需要時;否則建議在字串常量中,使用 \x、\u 或 \U 等轉義字符來表示非 ASCII 資料。
對於 Python 3.0 或以上版本,標準程式庫規定使用以下方針(參考 PEP 3131):所有 Python 標準程式庫中的識別字「必須」使用僅含 ASCII 的識別字,而且「應該」在可能的時候都用英文的單字(很多情況下所用的縮寫或技術術語並不是英語)。另外,字串常量或註解也都必須是 ASCII 編碼。例外情況只能是 (a) 測試非 ASCII 功能的測試案例,和 (b) 作者的名字。名字不是拉丁字母組成的作者,「必須」提供名字的拉丁音譯。
對於擁有全球性使用者的開放原始碼專案,也鼓勵採用類似的方針。
這樣寫:
import os import sys
不要寫:
import sys, os
但這種情況是可以的:
from subprocess import Popen, PIPE
import 應該以以下順序分組:
每組 import 之間應該以一個空白行分隔。 將任何相關的 __all__ 細述放在 import 之下。
所有 import 都要永遠用 package 的絕對路徑。雖然現在 PEP 328 [7] 已經在 Python 2.5 中完全實作,但它明確表明相對 import 的方式仍不鼓勵使用;絕對 import 更有可攜性,通常也更有可讀性。
from myclass import MyClass from foo.bar.yourclass import YourClass
如果會造成命名衝突,可以改成
import myclass import foo.bar.yourclass
然後使用 "myclass.MyClass" 和 "foo.bar.yourclass.YourClass"
惱人瑣事
在以下情況避免使用額外的空白:
這樣寫:
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
這樣寫:
spam(1)
不要寫:
spam (1)
這樣寫:
dict['key'] = list[index]
不要寫:
dict ['key'] = list [index]
這樣寫:
x = 1 y = 2 long_variable = 3
不要寫:
x = 1 y = 2 long_variable = 3
其他建議
這樣寫:
i = i + 1 submitted += 1 x = x * 2 - 1 hypot2 = x * x + y * y c = (a + b) * (a - b)
不要寫:
i=i+1 submitted +=1 x = x*2 - 1 hypot2 = x*x + y*y c = (a+b) * (a-b)
這樣寫:
def complex(real, imag=0.0): return magic(r=real, i=imag)
不要寫:
def complex(real, imag = 0.0): return magic(r = real, i = imag)
這樣寫:
if foo == 'blah': do_blah_thing() do_one() do_two() do_three()
盡量不要寫:
if foo == 'blah': do_blah_thing() do_one(); do_two(); do_three()
雖然有時 if/for/while 的主體短,可以整個放在同一行,但絕對不要在多子句時這麼做。也要避免摺疊這類長行!
盡量不要寫:
if foo == 'blah': do_blah_thing() for x in lst: total += x while t < 10: t = delay()
更是別寫:
if foo == 'blah': do_blah_thing() else: do_non_blah_thing() try: something() finally: cleanup() do_one(); do_two(); do_three(long, argument, list, like, this) if foo == 'blah': one(); two(); three()
註解和程式碼牴觸比沒有註解還糟。更改程式碼之後,永遠將更新註解列為優先事項。
註解應該是完整的句子。當註解是片語或句子時,第一個單字應該大寫,除非它是一個小寫開頭的識別字(絕對不要改變識別字的大小寫!)。
果註解很短,結尾的句點可以省略。區塊註解通常包含由完整句子組成的一或多個段落,其中每個句子都該以句點作結尾。
每個句子的句點後應該加兩個空白。
寫英文時,Strunk 和 White 的 "The Elements of Style" 值得參考。
非英語系國家的 Python 程式設計師:請用英文寫註解,除非 120% 確定不會有不懂你語言的人閱讀你的程式碼。
區塊註解
區塊註解通常用來註解下方的一段(或全部)程式碼,並和程式碼使用相同縮排層級。區塊註解的每一行開頭都是 # 和一個空白(除非該行在註解中需要縮排)。
區塊註解中的段落之間,以只有一個 # 的行分隔。
行內註解
有節制地使用行內註解。
行內註解是和 statement 在同一行的註解。行內註解和 statement 之間應該至少用兩個空白分隔。行內註解的開頭應該是 # 和一個空白。
行內註解若只陳述明顯事實,則是不必要且實際上是造成干擾的。不要這樣寫:
x = x + 1 # Increment x
但有時,這樣是有用的
x = x + 1 # Compensate for border
好的文件字串(即 docstring)撰寫慣例載於 PEP 257 [3]。
"""Return a foobang Optional plotz says to frobnicate the bizbaz first. """
如果需要在原始檔中加進 Subversion、CVS 或 RCS 的資料,可以這樣做:
__version__ = "$Revision: 60919 $" # $Source$
這幾行應該放在 module 的 docstring 之下,而在其他程式碼之前,並在上下各以一個空白行分隔。(譯註:Subversion 的話,第二行應該可以改用 "# $Id$")
Python 程式庫的命名慣例有點混亂,所以不太可能讓它完全一致 -- 不過這裡提供的是目前建議的命名標準。新的 module 和 package(包括第三方 framework)都應該依此標準撰寫,不過當現存的程式庫用的是不同風格時,保持內部的一致性比較重要。
命名風格敘述
有許多不同的命名風格,不論用在何處,能夠將它們辨認出來會很有幫助。
以下命名風格通常可以分辨出來:
注意:如果有縮寫字,將縮寫字的每個字母大寫。也就是寫 HTTPServerError 比 HttpServerError 好。
也有一種風格是用一個獨特的短字首將相關的名稱歸類在一起。這方法在 Python 中用得不多,但為了完整還是需要一提。例如 os.stat() function 回傳一個 tuple,其中各項的名稱習慣上都類似 st_mode,st_size,st_mtime 之類。(這是為了強調這些欄位和 POSIX system call struct 的對應關係,幫助程式設計師熟悉。)
X11 程式庫的所有 public function 都以 X 開頭。在 Python 中,這種風格通常是不需要的,因為 attribute 和 method 名稱前面都會接物件名稱,而 function 名稱前面則會接 module 名稱。
另外,以下是幾種開頭或結尾加底線的特殊格式(這些通常可以和任何大小寫慣例合用):
Tkinter.Toplevel(master, class_='ClassName')
命名慣例規範
避免使用的名稱
不要用單個 `l'(小寫 L)、`O'(大寫 o)、`I'(大寫 i)當變數名稱。
在某些字型,這些字元和數字的一和零難以分辨。需要暫時用 `l' 時,改用 `L'。
package 和 module 名稱
module 應該用全小寫的簡短名稱。若能增加可讀性,可以在其中加入底線。Python 的 package 也該用全小寫的簡短名稱,但底線不鼓勵使用。
因為 module 名稱對應到檔案名稱,而有些檔案系統不會區分大小寫且會將長名稱縮短,所以選擇相當簡短的 module 名稱很重要 -- 雖然這在 Unix 上不是問題,但會在需要將程式移植到舊的 Mac 或 Windows 版本以及 DOS 時產生問題。
當 C 或 C++ 寫的擴充 module 有對應的 Python module 提供高階介面(比較物件導向)時,C/C++ 的 module 開頭會有一個底線(像是 _socket)。
class 名稱
幾乎沒有例外,class 名稱使用字首大寫慣例。僅供內部用的 class,名稱前會加一個底線。
exception 名稱
因為 exception 必須是 class,class 的命名慣例在此適用。不過 exception 實際是代表錯誤時,名稱必須用 "Error" 當字尾。
全域變數名稱
(希望這些變數只是為了在一個 module 內部使用。)全域變數命名慣例幾乎和 function 一樣。
設計以 "from M import *" 使用的 module 應該用 __all__ 機制避免將全域變數匯出,或者按照較舊的慣例將這些全域變數字首都加一個底線(你可能也想藉此來將這些全域變數標示為「module 內部用」)。
function 名稱
function 名稱應該全部小寫,為了可讀性,單字間可用底線分隔。
mixedCase 只能用在這種風格已佔多數的程式碼中(例如 threading.py),或者為了保持相容性時。
function 和 method 參數
instance method 的第一個參數永遠用 'self'。
class method 的第一個參數永遠用 'cls'。
當 function 參數名稱和保留的關鍵字衝突時,在字尾加一個底線比用縮寫或拼寫省略好。因此 "print_" 比 "prnt" 好。(可能更好的是用同義字避免這類衝突。)
method 名稱和 instance 變數
使用 function 的命名規則:小寫並在需要時用底線分隔單字增加可讀性。
只有非 public 的 method 和 instance 變數才在開頭加一個底線。
為了避免和 subclass 衝突,可在開頭加雙底線以利用 Python 的 name mangling 機制。
Python 會用 class 名稱 mangle 這些雙底線開頭的名稱:如果 class Foo 有個叫做 __a 的 attribute,它無法以 Foo.__a 存取。(執意存取的使用者可以透過 Foo._Foo__a 存取。)一般而言,雙底線開頭只應該用在避免為繼承設計的 class 的 attribute 名稱衝突。
注意:雙底線開頭的名稱有一些爭議(見下方)。
為繼承而設計
永遠決定好 class 的 method 和 instance 變數(全部統稱為:attribute)是該 public 或非 public。不確定時,選擇非 public;在之後將它改成 public 比將 public attribute 改成非 public 容易。
public attribute 是在保證不會有不相容變動下,預計供 class 的不相關用戶使用的。非 public attribute 則是不打算供第三方使用;不需要保證非 public 的 attribute 不會變動或甚至移除。
這裡不用 "private" 這個詞,是因為 Python 中沒有任何 attribute 可以真正是 private(若不費一番不必要的苦工)。
另一類 attribute 是那些屬於 "subclass API" 的一部分的(在其他語言通常叫做 "protected")。有些 class 是專門設計成要被繼承,以擴展或修改 class 的功能。設計這種 class 時,注意明確地決定哪些 attribute 是 public,哪些是 subclass API 的一部分,哪些則是只供 class 本身使用。
謹記這些 Pythonic 指導原則:
注意:參考上面有關 class method 參數名稱的建議。
舉例來說,不要依賴 CPython 對像 a+=b 或 a=a+b 這類形式的 statement 的高效能就地字串串接實作。這些 statement 在 Jython 中執行比較慢。在程式庫效能要求高的部分,應該使用 ''.join() 形式。這樣可以確保串接在各種實作中,都只耗費線性時間。
也要注意寫了 "if x" 但其實是想表達 "if x is not None" 的情況 -- 例如,測試預設值是 None 的變數或參數是否設了新值時。新值可能是在邏輯判斷中有機會被當作 false 的型別(例如容器)!
字串型 exception 在新程式碼中禁止使用,因為這功能將在 Python 2.6 移除。 module 和 package 應該定義它們自己特定的基礎 exception class,這些 class 應該是內建 Exception class 的 subclass。永遠寫上 class 的文件字串。例如:
class MessageError(Exception): """Base class for errors in the email package."""
class 命名慣例適用於此,只是如果 exception 是代表錯誤時,exception class 名稱字尾要加上 'Error'。非錯誤類的 exception 不需要加特定字尾。
推薦括號格式是因為,exception 參數很長或包含格式化字串時,由於有括號,可以不必用行接續字元。舊的格式將在 Python 3000 (譯註:3.0)中移除。
例如:
try: import platform_specific_module except ImportError: platform_specific_module = None
空的 'except:' 子句會捕捉 SystemExit 和 KeyboardInterrupt 這兩個 exception,造成 Control-C 無法中止程式,而且可能掩蓋住其他問題。如果想捕捉所有代表程式錯誤的 exception,可以用 'except Exception:'。
有個好的法則是限制空的 'except' 子句只能用在兩種情況:
這麼寫:
try: value = collection[key] except KeyError: return key_not_found(key) else: return handle_value(value)
不要寫:
try: # Too broad! (太廣!) return handle_value(collection[key]) except KeyError: # Will also catch KeyError raised by handle_value() # (也會捕捉到 handle_value() 發出的 KeyError) return key_not_found(key)
字串的 method 總是快得多,而且和 unicode 字串共用同樣的 API。需要相容於比 Python 2.0 舊的版本時,可以打破此規則。
startswith() 和 endswith() 更清楚明白且不容易出錯。例如:
這麼寫:
if foo.startswith('bar'):
不要寫:
if foo[:3] == 'bar':
唯一例外是你的程式碼必須在 Python 1.5.2 運行(希望不要)。
這麼寫:
if isinstance(obj, int):
不要寫:
if type(obj) is type(1):
檢查物件是不是字串的時候,別忘了它也可能是 unicode 字串!Python 2.3 中,str 和 unicode 有共同的 base class -- basestring,所以可以這樣寫:
if isinstance(obj, basestring):
Python 2.2 中,types module 裡為此用途定義了 StringTypes 型別:
from types import StringTypes if isinstance(obj, StringTypes):
Python 2.0 和 2.1 中,應該這麼寫:
from types import StringType, UnicodeType if isinstance(obj, StringType) or \ isinstance(obj, UnicodeType) :
這麼寫:
if not seq: if seq:
不要寫:
if len(seq) if not len(seq)
這麼寫:
if greeting:
不要寫:
if greeting == True:
更不要:
if greeting is True: