PEP8 - Python 程式碼風格指引(中文)

前言

PEP: 8
Title: Style Guide for Python Code
中文標題: Python 程式碼風格指引
Version: c451868df657
Last-Modified: 2016-06-08 10:43:53 -0400 (Wed, 08 Jun 2016)
Author: Guido van Rossum <guido at python.org>, Barry Warsaw <barry at python.org>, Nick Coghlan <ncoghlan at gmail.com>
中文翻譯: JiaYun <jiayun at gmail.com>, Jam Chih Yen Chen <jam.chen at gmail.com>
Status: Active
Type: Process
Content-Type: text/x-rst
Created: 05-Jul-2001
Post-History: 05-Jul-2001, 01-Aug-2013

簡介

本文件提供了Python主要發行標準程式庫中的Python程式碼的撰寫慣例,關於Python中C語言實作所用的撰寫慣例 請參考相關的PEP [1]

本文件和PEP 257(Decstring撰寫慣例)是改寫自Guido的Python風格指引文章,並加上一些Barry的風格指引 [2]的內容。

隨著編程語言本身的新慣例確立或舊慣例捨棄,本風格指引也會隨之更新。

許多專案都有自己的撰寫風格指引,在任何衝突的情況向,此風格指引應優先於其他專案。

愚蠢的一致性是一種小心眼的表現

Guido 的重要見解之一是「程式碼被閱讀的次數,遠大於被撰寫的次數」。提供本指引的目的是為了增加程式碼的可讀性,並使Python程式碼在各方面保持一致性。 正如PEP 20說的「可讀性很重要」。

風格指引關注的是一致性,和本風格指引保持一致性很重要,在專案中保持一致性又更重要。但在module或function中保持一致性則是最重要的。

然而知道什麼時候該要不一致(有時候風格指引建議就是不適合),當有疑惑時,運用你的最佳判斷力,看看其他例子並決定哪種最好看。需要的時候就儘管發問。

特別是不要為了遵從這份PEP而打破舊程式碼的兼容性。

還有其他一些忽略掉這份指引的理由:

  1. 當遵守指引會降低程式碼可讀性,特別是對於習慣這份PEP的人來說可讀性也變差的時候。
  2. 為了跟前後一些不遵守PEP的程式碼(或許是因為歷史因素)保值一致性時。雖然這也是一個清理別人雜亂程式碼的時機(在真正的Extreme Programming開發風格)。
  3. 因為後來的PEP更新,而導致之前程式碼反而沒有遵守PEP,並且沒有其他要修改程式碼的理由時。
  4. 當程式碼需要跟Python舊版本保持相容性時,且舊版Python不支援此風格指引所推薦的撰寫慣例時。

程式碼編排

縮排

每個縮排層級使用4個空格。

若程式碼過長而使用延長行斷行,且程式碼中參數或引數被切成不同行,則變數應該要上下對齊。不論是使用Python中,大中小括號的隱式行連結,或是使用凸排的形式。當使用凸排時應該要考量以下情況:第一行不應該有參數或引述,且相較於其他行(譯註:這裡應該是指除了參數引數的接下來那一行),縮排應該要再深一層來清楚的分辨這是一個連續程式碼的延長行。

正確:

# 與第一個變數對齊 foo = long_function_name(var_one, var_two,

var_three, var_four)

# 往內再縮一層跟其他程式碼做區分 def long_function_name(

var_one, var_two, var_three, var_four):

print(var_one)

# 使用凸排,其餘往內縮一層 foo = long_function_name(

var_one, var_two, var_three, var_four)

錯誤:

# 沒有和第一行的引數對齊 foo = long_function_name(var_one, var_two,

var_three, var_four)

# 沒有往內再縮一層跟其他程式碼做區分 def long_function_name(

var_one, var_two, var_three, var_four): print(var_one)

「四個空白」原則在延長行中可用也可不採用。

可選:

# 凸排的內縮排可以使用其他空白數而非四個空白。 foo = long_function_name(

var_one, var_two, var_three, var_four)

當if語句的條件判斷部份過長需要被拆成多行時,需要特別注意的是開頭的「if (」會與原本if條件內開頭的四個空白形成一個自然的縮排對齊,這會跟if條件判斷需要斷行時也會有的開頭四個空白產生視覺衝突,本PEP對此情況(是否要進一步往內再縮一層跟其他程式碼做區分)沒有明確的規定。以下是一些可接收但不強制的選擇:

# 沒有進一步的縮排 if (this_is_one_thing and

that_is_another_thing): do_something()

# 在條件和內容之間加上註解,在某些針對註解有不同顏色的編譯器中提供一些區分。 if (this_is_one_thing and

that_is_another_thing): # Since both conditions are true, we can frobnicate. do_something()

# 在條件判斷延長行再多一層縮排。 if (this_is_one_thing

and that_is_another_thing):

do_something()

(也請參考下面對於是否要在二元運算子之前或之後斷行的討論。)

多行程式碼結尾若有「大中小括號」可以放在四個空牌後的第一個字元,如下:

my_list = [
1, 2, 3, 4, 5, 6, ]
result = some_function_that_takes_arguments(
‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, )

也可以放在跟第一行對其的第一個字元,如下:

my_list = [
1, 2, 3, 4, 5, 6,

] result = some_function_that_takes_arguments(

‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’,

)

tab 或空白?

空白是較為推薦的縮排方法。

若程式碼選擇使用Tab縮排,則後續的縮排應該也要使用Tab。

Python3不允許混用Tab和空白來縮排。

Python2的程式碼若有混用Tab和空白,則應該要轉換成都使用空白。

當使用-t參數來呼叫Python2直譯器時,它會對混用Tab和空白的程式碼發出警告,若是用-tt參數則這些警告會變成錯誤。強烈推薦使用這些參數。

每行最大長度

每行的最大長度應限制在79個字元以內。

對於較少結構限制(docstrings或註解)的大區塊文字,每行長度應限制在72字元以內。

限制編譯器的視窗寬度使其可以並排打開多個文件,或是可以使用code review工具來呈現兩個版本中相鄰列的差別。

大多數工具的預設排版會破壞程式碼的可視化結構,使其更難理解。所以要設定每行限制來避免讓一些預設視窗寬度為80的編譯器啟動自動排版,即使編輯器在排版時把標記字元放在最後一列中。一些網頁版的編輯器不會提供動態的程式碼排版。

為了更好的程式碼維護或是其他原因,一些團隊強烈的偏好更長的程式碼長度,在達成共同的協議下,可以把長度增加到100字元(就可以把長度增加到99字元),而docstrings和註解依舊是72字元限制。

Python標準函式庫是需要限制程式碼在79字元以內,而docstrings和註解則是限制在72字元以內。

過長程式碼的建議斷行方式是使用Python隱式行的大中小括號,程式碼也可以對expression使用小括號來分成多行,但此時偏好使用反斜線斷行。

有時候使用反斜線可能更適合,像是一個過長的敘述語句述是不能使用隱式行的,所以只能使用反斜線:

with open(‘/path/to/some/file/you/want/to/read’) as file_1,
open(‘/path/to/some/file/being/written’, ‘w’) as file_2:

file_2.write(file_1.read())

(參考前面關於if語句拆成多行的討論,以進一步思考這種多行語句的縮排方式。)

其他像是assert敘述的類型。

確保多行程式碼時,接續行的縮排機制。

是否要在二元運算子之前或之後斷行

幾十年來推薦的風格是在二元運算子之後斷行。但這會損害兩種可讀性:運算子傾向分散在視窗上的不同的列位置上,且每個運算子會被留在上一行,跟運算元分開。下面這個例子眼睛需要額外的分辨哪個運算元是被加或是被減。

# 錯誤:運算子離運算元很遠 income = (gross_wages +

taxable_interest + (dividends - qualified_dividends) - ira_deduction - student_loan_interest)

為了解決這個可讀性問題,數學家和出版商遵守相反的慣例,Donald Knuth這樣解釋他電腦中的傳統規則和排版方式:「雖然一個段落中的公式總是在二元運算或關係之後被斷航,但顯示時公式需要在二元運算之前斷行。[3]」。

遵守傳統的數學形式可成就有更多可讀性程式碼:

# 正確:更容易把運算元和運算子連結起來

income = (gross_wages
  • taxable_interest
  • (dividends - qualified_dividends)
  • ira_deduction
  • student_loan_interest)

空白行

將最高層的function和class定義以兩個空白行分隔。

class中的function用一個空白行分隔。

額外的空白行可以(謹慎地)用來分隔不同群組的相關function,在一群相關的單行程式碼中(例如一組虛擬實作),則可以省略空白行。

在function中謹慎地使用空白行來表示邏輯上的分段。

Python把control-L(也就是^L)換頁字元當成空白。許多工具將這字元當作換頁字元,所以你可以使用它來當作換頁字元,來為檔案中的相關的區段做分頁區隔開來。注意,一些編輯器和網頁版程式碼預覽工具並不會把control-L當作是換頁字元,並且會在該位置顯示成其它字元。

檔案編碼

Python發佈版的核心程式碼中應該始終使用UTF-8(或是Python2中使用ASCII)。

使用ASCII(在Python2中)或UTF-8(在Python3中)的檔案不應該具有編碼的宣告。

在標準函式庫中,非預設的編碼應該只在測試目的或是當註解或docstring需要提到包含非ASCII字元的作者名字時被使用。否則使用x、u、U或N在字串中包含非ASCII資料是比較建議的方式。

對於Python 3.0及更高版本,標準函式庫規定了以下策略(參考PEP3131):Python標準庫中的所有標識符必須都用ASCII字元,並且盡可能使用英文單詞(在許多情況下,縮寫和技術術語並不是英文)。此外,字串和註釋也必須是ASCII字元。唯一的例外是(a)測試非ASCII功能的案例,(b)作者名稱。名稱不是基於拉丁字母的作者必須提供其名字的拉丁音譯。

鼓勵全球觀眾的有開源專案採取類似的政策。

import

expression 和 statement 中的空白

惱人瑣事

其他建議

註解

區塊註解

行內註解

文件字串

版本紀錄

命名慣例

命名風格敘述

命名慣例規範

避免使用的名稱

package 和 module 名稱

class 名稱

exception 名稱

全域變數名稱

function 名稱

function 和 method 參數

method 名稱和 instance 變數

為繼承而設計

程式撰寫建議

References