目錄如下:
- Why We Need PEP 8
- Naming Conventions
- Code Layout
- Comments
- Whitespace in Expressions and Statements
- Programming Recommendations
- When to Ignore PEP 8
- Tips and Tricks to Help Ensure Your Code Follows PEP 8
- Conclusion
PEP 8
有時候讀作PEP8
或者PEP-8
,是一份提供如何編寫Python代碼指南和最佳實踐的文檔,由Guido van Rossum, Barry Warsaw, Nick Coghlan
在2001年完成。PEP 8
主要注重于提高 Python 代碼的可讀性和一致性。
PEP
全稱為:Python Enhancement Proposal
,一個PEP是一份文檔,它描述了為Python提出的新特性以及為社區編寫的Python方面的文檔,比如設計和風格。
本教程概述了PEP 8
中列出的關鍵指南,它的目標讀者是初級到中級程序員,因此我沒有涉及一些最高級的主題。不過你可以通過閱讀完整的PEP 8 — Style Guide for Python Code | Python.org文檔來學習高級主題。
在本教程結束時,你將能夠:
- 編寫遵從
PEP 8
規范的代碼 - 理解
PEP 8
中列出的指導原則背后的原因 - 設置你的開發環境,以便開始編寫符合
PEP 8
標準的Python代碼
Why We Need PEP 8
可讀性很重要
PEP 8
規范存在的目的在于提高Python代碼的可讀性,但為什么可讀性如此重要?為什么編寫具有可讀性的代碼是Python語言的指導原則之一?
正如Guido van Rossum
所說:”代碼閱讀的頻率遠遠高于編寫的頻率“。你可能花費幾分鐘或一整天時間編寫一段代碼來處理用戶身份驗證,一旦你寫完它,你就再也不會重寫一次,但是你肯定會再讀一次,這段代碼可能仍然是你正在進行的項目的一部分。每次你回到那個代碼文件,你必須要記住那部分代碼是做什么的以及你為什么要寫它,所以可讀性很重要。
如果你是Python新手,在你編寫代碼之后的幾天或幾周內還要你記住代碼片段的含義可能有點困難。如果你遵循PEP 8
標準,你可以很確定你對你的變量命名得很好,你會知道你添加了足夠的空格,因此更容易遵循代碼中的邏輯步驟,你還可以對你的代碼進行很好的注釋,所有的這些都意味著你的代碼具有更高的可讀性,也更容易再次閱讀。作為初學者,遵循PEP 8
的規則可以使學習Python成為更愉快的任務。
如果你正在找工作,那么遵循PEP 8
標準尤為重要,編寫清晰可讀性高的代碼更會突出你的專業性,這將會側面告訴你的老板,你了解怎么很好地構建你的代碼。
如果你擁有很多編寫Python代碼的經驗,然后你可能需要和其他人協作開發,編寫可讀性高的代碼在這里至關重要,其他人可能此前從未看過你這樣風格的代碼,他必須重新閱讀且理解你的代碼風格,如果擁有你遵循和認可的指南將使其他人更容易閱讀你的代碼。
Naming Conventions
明了勝于晦澀
當你編寫Python代碼的時候,你必須對很多東西命名:變量、函數、類、包等等,選擇合理的名字將為你節省時間和精力。你將能夠從名稱中找出某個變量,函數或類所代表的含義。你還要避免使用不恰當的名稱,因為這樣可能會導致難以調試的錯誤。
::Note: 永遠不要使用 i,o,或 I 單字母名稱,因為這些名稱可能會被誤認為1和0,具體取決于字體:::
# 這可能看起來像你試圖將2重新分配給零
0 = 2
Naming Styles
下表概述了Python代碼中的一些常見命名風格以及何時應該使用它們:
這些是一些常見的命名約定以及如何使用它們的示例,但是為了編寫高可讀性代碼,你仍然需要謹慎選擇字母和單詞。除了在代碼中選擇正確的命名風格外,還必須仔細選擇名稱,以下是有關如何盡可能有效地執行此操作的一些指示。
How to Choose Names
為變量、函數、類等選擇名稱是一項挑戰,在編寫代碼時,你應該在命名選擇中加入相當多的思考,因為這樣可以使代碼更具可讀性。在Python中為對象命名的最佳方法是使用描述性名稱來清楚表明對象所代表的內容。
對變量進行命名時,你可能會選擇簡單的單字母小寫名稱,例如x。但是,除非你使用x作為數學函數的參數,否則并不清楚x代表什么。想象下你正在將一個人的名字保存為字符串,并且你希望使用字符串切片來格式化其名稱。你最終會得到這樣的東西:
# Not recommended
x = 'John Smith'
y, z = x.split()
print(z, y, sep=', ')
# 'Smith, John'
上面代碼可以很好的運行,但是你必須追蹤x,y,z
表示的含義,這樣也會讓你的代碼協作者產生困擾,更明確的名稱選擇將是這樣的:
# Recommended
name = 'John Smith'
first_name, last_name = name.split()
print(last_name, first_name, sep=', ')
# 'Smith, John'
同樣,為了減少輸入的數量,在選擇名稱時使用單詞縮寫也是很有誘惑力的,在下面的例子中,我定義了一個函數db()
,它接受一個參數x并將其加倍返回:
# Not recommended
def db(x):
return x * 2
乍一看,這似乎是一個明智的選擇。 db()
很容易看成是double
的縮寫,但想象一下,幾天后再看這段代碼,你可能已經忘記了你試圖通過這個函數實現的目標是什么,這將使猜測它原本的含義變得困難。
下面的例子就比較清晰,如果你幾天后再看這段代碼,你仍然可以閱讀并理解此函數的目標:
# Recommended
def multiply_by_two(x):
return x * 2
同樣的理念適用于Python中的所有其他數據類型和對象,盡量一直使用最簡潔且最具描述性的名稱。
Code Layout
優美勝于丑陋
如何對代碼布局對于提升它的可讀性有很大的作用。在本節中,你將學習如何添加垂直空格以提高代碼的可讀性。你還將學習如何處理PEP 8
中建議的79字符行限制。
Blank Lines
垂直空格或空行可以極大地提高代碼的可讀性,聚集在一起的代碼可能是壓倒性的且難以閱讀,同樣,代碼中的空行太多會使其看起來非常稀疏,讀者可能需要進行沒必要的滾動,以下是關于如何使用垂直空白的三個關鍵指南。
用兩個空行包圍頂級函數和類,頂級函數和類應該是完全自包含的,并處理單獨的功能,在它們周圍放置額外的垂直空間是有意義的,因此很明顯它們是分開的:
class MyFirstClass:
pass
class MySecondClass:
pass
def top_level_function():
return None
用一個空行包圍類中的方法定義,在一個類中,函數都彼此有聯系,最好只在它們之間留一行:
class MyClass:
def first_method(self):
return None
def second_method(self):
return None
在函數內部謹慎地使用空行,以顯示清晰的步驟,有時候一個復雜的函數必須在return語句之前完成好幾個步驟,為了幫助閱讀者理解函數里面的邏輯,在每個步驟之間留一個空行會很有幫助。
在下面的示例中,有一個計算列表方差的函數,這個問題可以分為兩個步驟,所以我在每個步驟之間留下了一個空行,在return語句之前還有一個空行。這有助于讀者清楚地看到返回的內容:
def calculate_variance(number_list):
sum_list = 0
for number in number_list:
sum_list = sum_list + number
mean = sum_list / len(number_list)
sum_squares = 0
for number in number_list:
sum_squares = sum_squares + number**2
mean_squares = sum_squares / len(number_list)
return mean_squares - mean**2
如果仔細地使用垂直空格,可以大大提高代碼的可讀性,它有助于讀者直觀地理解你的代碼如何分成幾個部分,以及這些部分如何相互關聯。
Maximum Line Length and Line Breaking
PEP 8
建議每行代碼限制在79個字符以內,這是因為它允許多個文件并排打開,同時也避免了換行,當然,將語句保持在79個字符以內并不總是可行的。PEP 8
概述了允許語句在多行上運行的方法。
如果代碼包含在括號、方括號或大括號中,Python將會認為代碼是一行的:
def function(arg_one, arg_two,
arg_three, arg_four):
return arg_one
如果不能用上述的方式進行每行代碼延續,那么可以使用反斜杠代替換行:
from mypkg import example1, \
example2, example3
但是,如果可以使用第一個方案,那么就應該盡量這樣做。
如果需要在二元運算符周圍做換行操作,例如+
和*
,那么需要將換行操作放在前面,這條規則源于數學,數學家同意在二元運算符之前換行以可提高可讀性,比較以下兩個例子。
下面是在二元運算符之前換行的示例:
# Recommended
total = (first_variable
+ second_variable
- third_variable)
你可以馬上反應過來哪些變量正在相加后者相減,因為操作符緊鄰著變量。
現在,讓我們看一個在二元運算符之后換行的示例:
# Not Recommended
total = (first_variable +
second_variable -
third_variable)
在這里,很難看出哪個變量被加,哪個變量被減。
在二元運算符之前換行可以讓代碼更加具有可讀性,所PEP 8
鼓勵這種方式。在二元運算符之后換行的代碼仍然符合PEP 8
,但是,我們鼓勵你在二元運算符之前換行。
Indentation
當存在多種可能,不要嘗試去猜測
而是盡量找一種,最好是唯一一種明顯的解決方案(如果不確定,就用窮舉法)
縮進,即前導空格,在Python中非常重要。Python中代碼行的縮進級別決定了語句如何組合在一起。
思考下面的例子:
x = 3
if x > 5:
print('x is larger than 5')
縮進的print語句使得Python明白只有if語句返回True才能繼續執行它,同樣的縮進適用于告訴 Python 在調用函數時要執行哪些代碼,或者哪些代碼屬于給定的類。
PEP 8
制定的關鍵縮進規則如下:
- 使用4個連續的空格來表示縮進。
- 選擇空格而不是制表符(Tab)。
Tabs vs. Spaces
如同上述所說,當你進行縮進的時候,你最好用空格代替制表符,你可以直接對文本編輯器的設置進行調整,當你按Tab
的時候轉換為4個空格的輸出
如果你使用的是Python 2并且混合使用了制表符和空格來縮進代碼,當你運行的時候可能不會看見錯誤。為了幫助你檢查一致性,可以在從命令行運行Python 2代碼時添加-t
標志。當你不一致地使用制表符和空格時,解釋器將會發出警告:
python2 -t code.py
code.py: inconsistent use of tabs and spaces in indentation
相反,如果你使用-tt
標志,解釋器將發出錯誤而不是警告,使用此方法的好處是解釋器會告訴你縮進不一致的位置在哪里:
python2 -tt code.py
File "code.py", line 3
print(i, j)
^
TabError: inconsistent use of tabs and spaces in indentation
Python 3不允許制表符和空格混合使用,因此,如果你使用的是Python3,解釋器將會自動報錯:
python3 code.py
File "code.py", line 3
print(i, j)
^
TabError: inconsistent use of tabs and spaces in indentation
你可以在編寫Python代碼中使用制表符或空格來表示縮進,但是,如果你使用的是Python 3,則必須與你的選擇保持一致,否則你的代碼將不能運行。PEP 8
推薦你總是使用4個連續的空格來表示縮進。
Indentation Following Line Breaks
當你為了保證每行在79個字符以下而進行換行時,使用縮進來提高代碼可讀性是很有用的,它允許讀者區分兩行代碼和跨越兩行的單行代碼,這里有兩種縮進風格供你選擇。
第一個是將縮進塊與開始的分隔符對齊:
def function(arg_one, arg_two,
arg_three, arg_four):
return arg_one
有時你會發現只需要4個空格就可以與開口分隔符對齊,這種情況經常發生在 if 語句中,如果跨多行的if+ +(
構成4個字符,那么就會發生這種情況,在這種情況下,很難確定 if 語句中嵌套的代碼塊從哪里開始:
x = 5
if (x > 3 and
x < 10):
print(x)
在這種情況下,PEP 8
提供了兩種替代方案來幫助你提高代碼可讀性:
- 在最后的條件后添加注釋,由于大多數編輯器中有語法高亮顯示,這可以將條件與嵌套代碼分開:
x = 5
if (x > 3 and
x < 10):
# Both conditions satisfied
print(x)
- 在換行中添加額外的縮進:
x = 5
if (x > 3 and
x < 10):
print(x)
換行符后的另一種縮進方式是懸掛縮進(hanging indent),這是一個印刷術語,意思是段落或語句中除第一行以外的每一行都縮進,可以使用懸掛縮進直觀地表示一行代碼的延續。下面是一個例子:
var = function(
arg_one, arg_two,
arg_three, arg_four)
::Note:當你正在使用hanging indent時,第一行不得有任何參數。以下示例不符合PEP 8::
# Not Recommended
var = function(arg_one, arg_two,
arg_three, arg_four)
使用hanging indent時,可以添加額外的縮進以區分連續行與函數內包含的代碼。下面是一個難以閱讀的例子,因為函數里面的代碼和連續行的縮進等級是相同的:
# Not Recommended
def function(
arg_one, arg_two,
arg_three, arg_four):
return arg_one
相反,最好在一行代碼換行后使用雙縮進,這有助于你區分函數參數和函數內部構造,從而提高可讀性:
def function(
arg_one, arg_two,
arg_three, arg_four):
return arg_one
當你編寫遵循PEP 8
規范代碼的時候,每行字符在79之內的規則使你必須強制換行,為了提高可讀性,你應該縮進一行,以表明它是一個連續的行。做到這一點有兩種方法,第一種是將縮進的塊與開始的分隔符對齊,第二種是使用懸掛縮進,在換行之后,你可以自由選擇使用哪種方法進行縮進。
Where to Put the Closing Brace
一行代碼的換行操作允許你在括號、方括號或大括號后面斷開一行,這會造成一個問題,就是很容易忘記關閉括號,但重要的是要把它放在合理的地方,否則,它會使讀者感到困惑,Pep 8
為隱含的行延續中的結束括號的位置提供了兩個選項:
- 使用前一行的第一個非空白字符排列右括號:
list_of_numbers = [
1, 2, 3,
4, 5, 6,
7, 8, 9
]
- 將結束括號與聲明行的第一個字符對齊:
list_of_numbers = [
1, 2, 3,
4, 5, 6,
7, 8, 9
]
你可以自由地選擇任何一種方式,但是,和之前說的一樣,一致性是關鍵,所以之后的代碼就要堅持使用你選擇的某一個方案以保持代碼一致性。
Comments
如果你無法向人描述你的方案,那肯定不是一個好方案;反之亦然
你應該使用注釋來說明編寫的代碼,這對記錄你的代碼非常重要,這樣你的任何協作者都可以理解它。當你或者其他人閱讀代碼注釋,他們應該能夠很容易地理解注釋所應用的代碼,以及它如何與代碼的其余部分相匹配。
下面是一些你為你代碼作注釋時候需要注意的關鍵點:
- 將注釋和文檔字符串的行長限制為72個字符
- 使用完整的句子,以大寫字母開頭
- 注釋隨著代碼的更新而更新
Block Comments
使用塊注釋來記錄一小部分代碼,當你必須編寫幾行代碼來執行單個操作時,它們非常有用,例如從文件導入數據或更新數據庫記錄。其重要性在于它們可以幫助其他人理解給定代碼塊的用途和功能。
PEP 8
提供以下規則來編寫注釋:
- 將塊注釋縮進到其描述代碼的相同級別
- 用#加上一個空格開始每一行的注釋
- 用包含單個#的行分隔段落
這是一個解釋for循環功能的塊注釋,請注意,句子為了每行保留79個字符行限制進行了換行:
for i in range(0, 10):
# Loop over i ten times and print out the value of i, followed by a
# new line character
print(i, '\n')
有時,如果代碼技術性較強,那么有必要在塊注釋中使用多個段落:
def quadratic(a, b, c, x):
# Calculate the solution to a quadratic equation using the quadratic
# formula.
#
# There are always two solutions to a quadratic equation, x_1 and x_2.
x_1 = (- b+(b**2-4*a*c)**(1/2)) / (2*a)
x_2 = (- b-(b**2-4*a*c)**(1/2)) / (2*a)
return x_1, x_2
如果你不確定什么樣的注釋類型是合適的,那么塊注釋通常是正確的選擇。請盡量在你的代碼中添加注釋,一旦你對代碼進行了更新也請務必對注釋進行更新!
Inline Comments
行內注釋對單個語句中的一段代碼進行了解釋,這有助于提醒你或者其他人為什么某行代碼是必須的,以下是 PEP 8
對他們的評價:
- 謹慎使用行內注釋
- 在與它們引用的語句相同的行上寫入行內注釋
- 從語句中用兩個或多個空格分隔行內注釋
- 像塊注釋那樣,用#加上一個空格開始每一行的注釋
- 不要用它們來解釋明顯的問題
下面是一個行內注釋的例子:
x = 5 # This is an inline comment
有時,行內注釋似乎是必要的,但是你可以使用更好的命名約定,下面是一個例子:
x = 'John Smith' # Student Name
這里,行內注釋為變量提供了額外的說明信息,然而用x
作為一個人名的變量名不是很好的做法,如果你對變量重命名,是可以不用使用行內注釋的:
student_name = 'John Smith'
最后,像這樣的行內注釋是不好的做法,因為它們陳述了顯而易見且雜亂的代碼:
empty_list = [] # Initialize empty list
x = 5
x = x * 5 # Multiply x by 5
行內注釋比塊注釋更具體,并且容易在非必要時候添加它們,這會導致代碼混亂。除非你確定需要行內注釋,不然使用塊注釋避免代碼混亂的問題比較好,堅持使用塊注釋,可以讓你的代碼更加符合PEP8
的標準。
Documentation Strings
Documentation strings
或者說docstrings
, 是用雙引號(”””)或單引號(’’’)括起來的字符串,它們出現在任何函數,類,方法或模塊的第一行,你可以使用它們來解釋和記錄特定的代碼塊。這里有一個對應的PEP
,見PEP 257,但你可以從本節閱讀總結的經驗:
使用文檔字符串的重要規則如下:
- 文檔字符串兩邊都有三個雙引號環繞,比如:
"""This is a docstring"""
- 為所有公共模塊,函數,類和方法編寫
docstrings
- 使用單行
"""
結束多行docstring
def quadratic(a, b, c, x):
"""Solve quadratic equation via the quadratic formula.
A quadratic equation has the following form:
ax**2 + bx + c = 0
There always two solutions to a quadratic equation: x_1 & x_2.
"""
x_1 = (- b+(b**2-4*a*c)**(1/2)) / (2*a)
x_2 = (- b-(b**2-4*a*c)**(1/2)) / (2*a)
return x_1, x_2
- 對于單行
docstrings
,保持"""
在同一行:
def quadratic(a, b, c, x):
"""Use the quadratic formula"""
x_1 = (- b+(b**2-4*a*c)**(1/2)) / (2*a)
x_2 = (- b-(b**2-4*a*c)**(1/2)) / (2*a)
return x_1, x_2
想要了解更多,請閱讀Documenting Python Code: A Complete Guide – Real Python
Whitespace in Expressions and Statements
間隔勝于緊湊
正確使用空格在表達式和語句中非常有用,如果代碼中沒有足夠的空格,那么代碼應該很難閱讀,因為他們都湊在一起,如果空格太多,又會難以在視覺上將完整的語句聯系出來。
Whitespace Around Binary Operators
在進行以下二元操作的時候,應該在其兩邊加上空格:
- 分配操作(=, +=, -=, 等等)
- 比較(==, !=, >, <. >=, <=)和 (is, is not, in, not in)
- 布爾(and, not, or)
::Note:當=
是為一個函數的參數賦值時候就不用在兩邊加空格::
# Recommended
def function(default_parameter=5):
# ...
# Not recommended
def function(default_parameter = 5):
# ...
如果語句中有多個運算符,則在每個運算符前后添加單個空格可能會讓人感到困惑,相反,最好只在優先級最低的運算符周圍添加空格,尤其是在執行數學運算時。以下是幾個例子:
# Recommended
y = x**2 + 5
z = (x+y) * (x-y)
# Not Recommended
y = x ** 2 + 5
z = (x + y) * (x - y)
還可以將此應用于有多個條件的if語句:
# Not recommended
if x > 5 and x % 2 == 0:
print('x is larger than 5 and divisible by 2!')
在上面的示例中,and
操作具有最低優先級,因此,可以下面這樣更清楚地表達if語句:
# Recommended
if x>5 and x%2==0:
print('x is larger than 5 and divisible by 2!')
你可以自由選擇哪個方式更清晰,但需要注意的是你必須在運算符的任何一側使用相同數量的空格。
下面的例子是不被允許的:
# Definitely do not do this!
if x >5 and x% 2== 0:
print('x is larger than 5 and divisible by 2!')
在切片中,冒號作為二元運算符。因此,上一節中概述的規則也適用于此,并且其任何一方都應該有相同數量的空白,以下列表切片示例是合法的:
list[3:4]
# Treat the colon as the operator with lowest priority
list[x+1 : x+2]
# In an extended slice, both colons must be
# surrounded by the same amount of whitespace
list[3:4:5]
list[x+1 : x+2 : x+3]
# The space is omitted if a slice parameter is omitted
list[x+1 : x+2 :]
總之,你應該使用空格包圍大多數運算符,但是,此規則有一些注意事項,例如在函數參數中或在一個語句中組合多個運算符時。
When to Avoid Adding Whitespace
在某些情況下,添加空格可能會使代碼難以閱讀,太多的空格會使代碼過于稀疏而難以理解。 PEP 8
概述了一些非常明顯的例子應當不使用空格
在一行的末尾避免添加空格是最重要的地方,這稱為trailing whitespace
,它是不可見的,可能產生難以追蹤的錯誤。
以下列表概述了一些應避免添加空格的情況:
- 直接放在括號、方括號或大括號內:
# Recommended
my_list = [1, 2, 3]
# Not recommended
my_list = [ 1, 2, 3, ]
- 在逗號,分號或冒號之前:
x = 5
y = 6
# Recommended
print(x, y)
# Not recommended
print(x , y)
- 在打開函數調用的參數列表的開括號之前:
def double(x):
return x * 2
# Recommended
double(3)
# Not recommended
double (3)
- 在開始索引或切片的開括號之前:
# Recommended
list[3]
# Not recommended
list [3]
- 在尾隨逗號和右括號之間:
# Recommended
tuple = (1,)
# Not recommended
tuple = (1, )
- 對齊賦值運算符:
# Recommended
var1 = 5
var2 = 6
some_long_var = 7
# Not recommended
var1 = 5
var2 = 6
some_long_var = 7
確保你的代碼中沒有尾隨空格。 在其他情況下,PEP 8
不鼓勵添加額外的空格,例如立直接放在括號、方括號或大括號內,以及逗號和冒號之前。 為了對齊操作符,也不應該添加額外的空格。
Programming Recommendations
簡潔勝于復雜
你經常會發現有幾種方法可以在 Python (以及任何其他編程語言)中執行類似的操作。在本節中,你將看到PEP 8
提供的一些建議用來消除這種歧義并且保持一致性。
不要使用等價運算符將布爾值與True或False進行比較,你經常需要檢查布爾值是True還是False,當這樣操作時,請使用如下所示的語句直觀地執行此操作:
# Not recommended
my_bool = 6 > 5
if my_bool == True:
return '6 is bigger than 5'
這里不需要使用等價運算符==
, bool只能取值True或False,按照下面這樣寫就行了:
# Recommended
if my_bool:
return '6 is bigger than 5'
這種在if語句中使用bool的方式可以寫更少的代碼并且更加簡單,因此PEP 8
鼓勵使用這種方式。
在if語句中判斷列表是否為空,當你希望確定列表是否為空時,你通常會判斷列表的長度,如果列表為空,那么長度為0,在if語句中使用時等于False,這里有一個例子:
# Not recommended
my_list = []
if not len(my_list):
print('List is empty!')
但是,在Python中,任何空列表,字符串或元組都可以當為False的。因此,我們可以提出一個更簡單的替代方案:
# Recommended
my_list = []
if not my_list:
print('List is empty!')
兩種方法都可以判斷列表是否為空,但是第二種方式更加簡潔,因此PEP 8
鼓勵使用這種方式。
在if語句中,使用 is not 比 no ... is in 好,當你需要確定一個變量是否被賦值,這里有兩種方法,第一種是評估if語句中的x是不是為非None
,如下所示:
# Recommended
if x is not None:
return 'x exists!'
第二種方案是現在if語句中判斷x是不是None
,再進行not
操作:
# Not recommended
if not x is None:
return 'x exists!'
兩種方法都可以判斷x是否為None
,但是第一種方式更加簡單,因此PEP 8
鼓勵使用這種方式。
當你想表達if x is not None時,不要使用if x,有時候,你可能擁有一個函數帶有默認值為None
的參數,當對參數arg
檢查是否帶有不同的值的時候經常會犯下面這樣的錯誤:
# Not Recommended
if arg:
# Do something with arg...
此代碼檢查的是arg
是否為真,但相對的你要的是檢查是否為None
,所以下面這樣寫比較好:
# Recommended
if arg is not None:
# Do something with arg...
上面的錯誤會使得判斷是否為真和not None
相等,你可以設置arg = []
,如上所述,空列表在Python中被認為是False
,因此,盡管參數被聲明為[]
,但條件并沒有滿足,因此函數里面的代碼if
聲明并不能被執行。
用.startswith() 和.endswith()代替切片,如果你想檢查一段字符串的前綴或者后綴是否帶有字符串cat
,這看起來使用列表切片似乎比較明智,但是,列表切片容易出錯,您必須對前綴或后綴中的字符數進行硬編碼,對于那些不太熟悉Python列表切片的人來說很難看清楚你想要實現的目的:
# Not recommended
if word[:3] == 'cat':
print('The word starts with "cat"')
然而,還是使用.startswith():
可讀性比較高:
# Recommended
if word.startswith('cat'):
print('The word starts with "cat"')
同樣的,當你想檢查字符串后綴也是同樣的原理,下面的示例概述了如何檢查字符串是否以jpg結尾:
# Not recommended
if file_name[-3:] == 'jpg':
print('The file is a JPEG')
雖然結果是正確的,但是符號有點復雜且難以閱讀,與之相對的,你可以用.endswith()
實現,看下面例子:
# Recommended
if file_name.endswith('jpg'):
print('The file is a JPEG')
就像上面的列出的編程建議,我們目標是編寫清晰以及可讀性較高的代碼,在Python中,有許多不同的方法可以實現相同的結果,因此有關選擇哪種方法的指南很有幫助。
When to Ignore PEP 8
什么時候忽略PEP 8?對于這個問題有個簡短的答案,那就是永遠不會
如果你嚴格遵循 PEP 8,就可以保證您擁有干凈、專業和可讀的代碼。 這對你以及合作者和潛在雇主都有好處。
但是,PEP 8中的一些指導方針在以下實例中不適用:
- 如果遵守PEP 8將破壞與現有軟件的兼容性
- 如果你正在從事的工作的代碼與 PEP 8不一致
- 如果代碼需要與舊版本的Python版本保持兼容
Tips and Tricks to Help Ensure Your Code Follows PEP 8
想要你的代碼兼容PEP 8
,那你得記住不少規范,在開發代碼時,記住所有這些規則可能是一項艱巨的任務。特別是對老項目進行更新以兼容PEP 8
時,幸運的是,有些工具可以幫助你加快這一過程,這里有兩個工具可以幫你強制兼容PEP 8
規范:linters
和autoformatters
。
Linters
Linters是分析代碼和標記錯誤的程序,他們可以為你如何修復錯誤提供建議,在作為文本編輯器的擴展安裝時,Linters特別有用,因為它們標記了你編程時的錯誤和格式問題。在本節中,您將看到Linters程序是如何工作的大綱,最后還有文本編輯器擴展的鏈接。
對于Python代碼,最好的linters如下:
- [pycodestyle](pycodestyle · PyPI)是一個根據
PEP 8
中的某些風格約定來檢查Python代碼的工具
# 使用pip安裝pycodestyle
pip install pycodestyle
使用以下命令在終端中使用pycodestyle
:
pycodestyle code.py
code.py:1:17: E231 missing whitespace after ','
code.py:2:21: E231 missing whitespace after ','
code.py:6:19: E711 comparison to None should be 'if cond is None:'
-
flake8是一個結合了調試器,
pyflakes
和pycodestyle
的工具
# 使用pip安裝flake8
pip install flake8
使用以下命令在終端中使用pycodestyle
:
flake8 code.py
code.py:1:17: E231 missing whitespace after ','
code.py:2:21: E231 missing whitespace after ','
code.py:3:17: E999 SyntaxError: invalid syntax
code.py:6:19: E711 comparison to None should be 'if cond is None:'
還顯示了輸出的示例。
::Note:額外輸出的一行表示語法錯誤。::
這些也可用作Atom,Sublime Text,Visual Studio Code和VIM的擴展。您還可以找到有關為Python開發設置Sublime Text和VIM的指南,以及Real Python中一些流行的文本編輯器的概述。
Autoformatters
Autoformatters
可以重構你的代碼以使其符合PEP 8
規范,像black程序就可以根據PEP 8
規范重新格式化你的代碼,一個很大的區別是它將行長度限制為88個字符,而不是79個字符。但是,您可以通過添加命令行標志來覆蓋它,如下面的示例所示。
可以使用pip安裝black,它需要Python 3.6+
:
pip install black
它可以通過命令行運行,就像Linters一樣。假設你從名為code.py里面不符合PEP 8規范的代碼開始:
for i in range(0,3):
for j in range(0,3):
if (i==2):
print(i,j)
你可以在命令行中運行如下代碼:
black code.py
reformatted code.py
All done!
code.py
將會被重新格式化為如下所示:
for i in range(0, 3):
for j in range(0, 3):
if i == 2:
print(i, j)
如果你想要更改行長度限制,則可以使用—line-length
標志:
black --line-length=79 code.py
reformatted code.py
All done!
另外兩個autoformatters
分別為autopep8
和yapf
,它們和black
操作類似。
另一個Real Python
教程,由Alexander van Tol
編寫的Python Code Quality: Tools & Best Practices詳細解釋了如何使用這些工具。
Conclusion
你現在已經知道如何使用PEP 8
中的指南編寫高質量,可讀高的Python代碼,雖然指南看起來很迂腐,但遵循它們可以真正改善你的代碼,特別是在與潛在雇主或合作者共享代碼時。
在本教程中你了解到:
- 什么是
PEP 8
以及其存在的原因 - 為什么你應該編寫符合
PEP 8
標準的代碼 - 如何編寫符合
PEP 8
的代碼
除此之外,您還了解了如何使用linters和autoformatters根據PEP 8
指南檢查代碼。
如果你想了解更多,可以閱讀[full documentation](PEP 8 — Style Guide for Python Code | Python.org)或者瀏覽pep8.org,這些教程不僅提供了類似的信息同時也提供了很好的格式讓你閱讀,在這些文檔中,您將找到本教程未涉及的其余PEP 8
指南。