以正確的方式建立Python註釋

以正確的方式建立Python註釋配圖

註釋是程式設計師在他們的程式碼中加入的註釋,以解釋該程式碼應該做什麼。將程式碼轉化為行動的編譯器或直譯器會忽略註釋,但它們對管理軟體專案是必不可少的。

註釋有助於向其他程式設計師解釋你的 Python 程式碼,並且可以提醒你為什麼做出這樣的選擇。註釋通過幫助未來的程式設計師理解軟體背後的設計選擇,使除錯和修改程式碼更加容易。

儘管註釋主要是為開發人員準備的,但編寫有效的註釋也可以幫助為你的程式碼的使用者製作優秀的文件。在Python專案的Sphinx等文件生成器的幫助下,你的程式碼中的註釋可以為你的文件提供內容。

讓我們來看看Python中的註釋是怎樣的。

Python中的註釋

根據Python PEP 8樣式指南,在寫註釋時有幾件事需要注意:

  • 註釋應該始終是完整而簡明的句子。
  • 沒有註釋總比有一個難以理解或不準確的註釋要好。
  • 註釋應該定期更新,以反映你的程式碼的變化。
  • 太多的註釋會使人分心並降低程式碼質量。如果程式碼的目的很明顯,就不需要註釋。

在Python中,當一行以 # 符號開始時,它就被宣告為註釋。當Python直譯器在你的程式碼中遇到 # 時,它將忽略該符號之後的任何內容,並且不會產生任何錯誤。有兩種方法來宣告單行註釋:內聯註釋和塊註釋。

內聯註釋

內聯註釋提供了對變數和簡單操作的簡短描述,與程式碼語句寫在同一行。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
border = x + 10 # Make offset of 10px
border = x + 10 # Make offset of 10px
border = x + 10  # Make offset of 10px

註釋在與程式碼相同的語句中解釋了程式碼的功能。

區塊註釋

區塊註釋用於描述程式碼中的複雜邏輯。Python 中的塊狀註釋的構造與內聯註釋類似 – 唯一的區別是塊狀註釋是寫在單獨的一行上。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import csv
from itertools import groupby
# Get a list of names in a sequence from the csv file
with open('new-top-firstNames.csv') as f:
file_csv = csv.reader(f)
# Skip the header part: (sr, name, perc)
header = next(file_csv)
# Only name from (number, name, perc)
persons = [ x[1] for x in file_csv]
# Sort the list by first letter because
# The groupby function looks for sequential data.
persons.sort(key=lambda x:x[0])
data = groupby(persons, key=lambda x:x[0])
# Get every name as a list
data_grouped = {}
for k, v in data:
# Get data in the form
# {'A' : ["Anthony", "Alex"], "B" : ["Benjamin"]}
data_grouped[k] = list(v)
import csv from itertools import groupby # Get a list of names in a sequence from the csv file with open('new-top-firstNames.csv') as f: file_csv = csv.reader(f) # Skip the header part: (sr, name, perc) header = next(file_csv) # Only name from (number, name, perc) persons = [ x[1] for x in file_csv] # Sort the list by first letter because # The groupby function looks for sequential data. persons.sort(key=lambda x:x[0]) data = groupby(persons, key=lambda x:x[0]) # Get every name as a list data_grouped = {} for k, v in data: # Get data in the form # {'A' : ["Anthony", "Alex"], "B" : ["Benjamin"]} data_grouped[k] = list(v)
import csv
from itertools import groupby
# Get a list of names in a sequence from the csv file
with open('new-top-firstNames.csv') as f:
file_csv = csv.reader(f)
# Skip the header part: (sr, name, perc)
header = next(file_csv)
# Only name from (number, name, perc)
persons = [ x[1] for x in file_csv]
# Sort the list by first letter because 
# The groupby function looks for sequential data.
persons.sort(key=lambda x:x[0])
data = groupby(persons, key=lambda x:x[0])
# Get every name as a list 
data_grouped = {}
for k, v in data:
# Get data in the form 
# {'A' : ["Anthony", "Alex"], "B" : ["Benjamin"]}
data_grouped[k] = list(v)

注意,當使用塊狀註釋時,註釋是寫在它們所解釋的程式碼上面的。Python PEP8 風格指南規定,一行程式碼不應包含超過79個字元,而內聯註釋常常使行數超過這個長度。這就是為什麼要寫塊狀註釋,在不同的行中描述程式碼。

多行註釋

Python 本身並不支援多行註釋,這意味著沒有專門的規定來定義它們。儘管如此,跨越多行的註釋經常被使用。

你可以通過在每一行前面加上 # 來建立一個多行註釋,而不是幾個單行註釋。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# interpreter
# ignores
# these lines
# interpreter # ignores # these lines
# interpreter 
# ignores
# these lines

你也可以使用多行字串的語法。在Python中,你可以用 """,三個雙引號,或 ''',三個單引號包圍它們來定義多行字串。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
print("Multi-Line Comment")
"""
This
String is
Multi line
"""
print("Multi-Line Comment") """ This String is Multi line """
print("Multi-Line Comment")
"""
This
String is 
Multi line 
"""

在上面的程式碼中,多行字串沒有分配給一個變數,這使得這個字串像一個註釋一樣工作。在執行時,Python 忽略了這個字串,它不會被包含在位元組碼中。執行上面的程式碼會產生下面的輸出。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Multi-Line Comment
Multi-Line Comment
Multi-Line Comment

特殊註釋

除了使你的程式碼具有可讀性外,註釋在Python中還有一些特殊的作用,如計劃未來的程式碼新增和生成文件。

Python文件串註釋

在 Python 中,docstrings 是多行註釋,解釋如何使用一個給定的函式或類。通過建立高質量的 docstrings,可以改善你的程式碼的文件。當使用一個函式或類並使用內建的 help(obj) 函式時,docstrings 可能有助於給出物件的概況。

Python PEP 257 提供了一種在 Python 中宣告 docstrings 的標準方法,如下所示:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
from collections import namedtuple
Person = namedtuple('Person', ['name', 'age'])
def get_person(name, age, d=False):
"""
Returns a namedtuple("name", "age") object.
Also returns dict('name', 'age') if arg `d` is True
Arguments:
name – first name, must be string
age – age of person, must be int
d – to return Person as `dict` (default=False)
"""
p = Person(name, age)
if d:
return p._asdict()
return p
from collections import namedtuple Person = namedtuple('Person', ['name', 'age']) def get_person(name, age, d=False): """ Returns a namedtuple("name", "age") object. Also returns dict('name', 'age') if arg `d` is True Arguments: name – first name, must be string age – age of person, must be int d – to return Person as `dict` (default=False) """ p = Person(name, age) if d: return p._asdict() return p
from collections import namedtuple
Person = namedtuple('Person', ['name', 'age'])
def get_person(name, age, d=False):
"""
Returns a namedtuple("name", "age") object.
Also returns dict('name', 'age') if arg `d` is True
Arguments:
name  – first name, must be string
age   – age of person, must be int
d     – to return Person as `dict` (default=False)
"""
p = Person(name, age)
if d:
return p._asdict()
return p

在上面的程式碼中,docstring提供了相關函式工作的細節。通過像Sphinx這樣的文件生成器,這個docstring可以用來給你專案的使用者一個如何使用這個方法的概述。

一個定義在函式或類簽名下面的文件串也可以通過使用內建的 help() 函式返回。 help() 函式接受一個物件或函式名稱作為引數,並將函式的文件串作為輸出返回。在上面的例子中,可以呼叫 help(get_person) 來顯示與 get_person 函式相關的文件串。如果你在互動式 shell 中使用  -i 標誌執行上面的程式碼,你可以看到這個 docstring 將如何被 Python 解析。通過輸入  python -i file.py 來執行上面的程式碼。

在命令列介面中解析的Python文件串註釋

在命令列介面中解析的Python文件串註釋

 help(get_person) 函式呼叫返回你的函式的文件串。輸出包含  get_person(name, age, d=False),這是一個 Python 自動新增的函式簽名。

get_person.__ doc__ 屬性也可以被用來以程式設計方式檢索和修改 docstring。在上面的例子中新增了 “一些更多的新資訊 “之後,它出現在對  help(get_person) 的第二次呼叫中。儘管如此,你不太可能需要像這樣在執行時動態地改變 docstrings。

TODO註釋

在編寫程式碼時,有時你會想突出某些行或整個塊來進行改進。這些任務是由TODO註釋來標記的。當你計劃更新或修改你的程式碼時,或者當你想通知專案的使用者或合作者檔案的特定部分的程式碼還沒有寫完時,TODO註釋就會很方便。

TODO註釋不應該被寫成虛擬碼–它們只需要簡單地解釋尚未編寫的程式碼的功能。

TODO註釋和單行塊註釋非常相似,它們之間唯一的區別是TODO註釋必須以TODO字首開始。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# TODO Get serialized data from the CSV file
# TODO Perform calculations on the data
# TODO Return to the user
# TODO Get serialized data from the CSV file # TODO Perform calculations on the data # TODO Return to the user
# TODO Get serialized data from the CSV file
# TODO Perform calculations on the data
# TODO Return to the user

值得注意的是,儘管許多 IDE 可以為程式設計師突出顯示這些註釋,但 Python 直譯器對 TODO 註釋的看法與塊註釋沒有任何區別。

編寫Python註釋時的最佳做法

在編寫註釋時,有一些最佳實踐應該被遵循,以確保可靠性和質量。下面是在Python中編寫高質量註釋的一些提示。

避免脫褲子放屁

那些陳述明顯的註釋並沒有給你的程式碼增加任何價值,應該避免使用。比如說:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
x = x + 4 # increase x by 4
x = x + 4 # increase x by 4
x = x + 4 # increase x by 4

這條註釋並不有用,因為它只是簡單地說明了程式碼的作用,而沒有解釋為什麼需要這樣做。註釋應該解釋 “為什麼”,而不是它們所描述的程式碼的 “什麼”。

改寫後更有用,上面的例子可能是這樣的:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
x = x + 4 # increase the border width
x = x + 4 # increase the border width
x = x + 4 # increase the border width

保持Python註釋簡明扼要

保持你的註釋簡短而容易理解。它們應該用標準的散文來寫,而不是用虛擬碼來寫,並且應該取代閱讀實際程式碼的需要,以獲得對程式碼的總體概述。太多的細節或複雜的註釋並不能使程式設計師的工作變得更容易。比如說:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# return area by performing, Area of cylinder = (2*PI*r*h) + (2*PI*r*r)
def get_area(r,h):
return (2*3.14*r*h) + (2*3.14*r*r)
# return area by performing, Area of cylinder = (2*PI*r*h) + (2*PI*r*r) def get_area(r,h): return (2*3.14*r*h) + (2*3.14*r*r)
# return area by performing, Area of cylinder = (2*PI*r*h) + (2*PI*r*r)
def get_area(r,h):
return (2*3.14*r*h) + (2*3.14*r*r)

上面的註釋為讀者提供了更多的資訊,而不是必要的資訊。註釋應該提供程式碼的一般總結,而不是指定核心邏輯。這條註釋可以改寫為

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# return area of cylinder
def get_area(r,h):
return (2*3.14*r*h) + (2*3.14*r*r)
# return area of cylinder def get_area(r,h): return (2*3.14*r*h) + (2*3.14*r*r)
# return area of cylinder
def get_area(r,h):
return (2*3.14*r*h) + (2*3.14*r*r)

謹慎地使用識別符號

在註釋中應謹慎使用識別符號。改變識別符號的名稱或情況會使讀者感到困惑。例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# return class() after modifying argument
def func(cls, arg):
return cls(arg+5)
# return class() after modifying argument def func(cls, arg): return cls(arg+5)
# return class() after modifying argument
def func(cls, arg):
return cls(arg+5)

上面的註釋提到了 class 和 argument,但這兩者在程式碼中都沒有找到。這條註釋可以改寫為:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# return cls() after modifying arg
def func(cls, arg):
return cls(arg+5)
# return cls() after modifying arg def func(cls, arg): return cls(arg+5)
# return cls() after modifying arg
def func(cls, arg):
return cls(arg+5)

DRY和WET原則

當你寫程式碼時,你要堅持DRY(不要重複自己)原則,避免WET(把所有東西都寫兩次)。

這對註釋來說也是如此。避免使用多個語句來描述你的程式碼,並儘量將解釋相同程式碼的註釋合併為一個註釋。然而,在合併註釋的時候一定要小心:不小心合併多個註釋會導致一個巨大的註釋,違反了風格指南,而且讀者很難理解。

記住,註釋應該減少程式碼的閱讀時間。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# function to do x work
def do_something(y):
# x work cannot be done if y is greater than max_limit
if y < 400:
print('doing x work')
# function to do x work def do_something(y): # x work cannot be done if y is greater than max_limit if y < 400: print('doing x work')
# function to do x work
def do_something(y):
# x work cannot be done if y is greater than max_limit
if y < 400:
print('doing x work')

在上面的程式碼中,註釋是不必要的零散的,可以合併成一個註釋。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# function to do x if arg:y is less than max_limit
def do_something(y):
if y in range(400):
print('doing x work')
# function to do x if arg:y is less than max_limit def do_something(y): if y in range(400): print('doing x work')
# function to do x if arg:y is less than max_limit
def  do_something(y):
if y in range(400):
print('doing x work')

一致的縮排

確保註釋的縮排程度與它們所描述的程式碼相同。如果不這樣做,就很難理解。

例如,這個註釋的縮排和定位都不正確:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
for i in range(2,20, 2):
# only even numbers
if verify(i):
# i should be verified by verify()
perform(x)
for i in range(2,20, 2): # only even numbers if verify(i): # i should be verified by verify() perform(x)
for i in range(2,20, 2):
# only even numbers
if verify(i):
# i should be verified by verify()
perform(x)

它可以改寫成如下樣子:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# only even numbers
for i in range(2,20, 2):
# i should be verified by verify()
if verify(i):
perform(x)
# only even numbers for i in range(2,20, 2): # i should be verified by verify() if verify(i): perform(x)
# only even numbers
for i in range(2,20, 2):
# i should be verified by verify()
if verify(i):
perform(x)

小結

註釋是編寫可理解程式碼的一個重要組成部分。你在寫註釋方面的投資是你未來的自己–或其他需要在你的程式碼庫上工作的開發者–會欣賞的。註釋還可以讓你對你的程式碼有更深入的瞭解。

在本教程中,你已經瞭解了更多關於Python中的註釋,包括各種型別的Python註釋,何時使用每種註釋,以及建立註釋時應遵循的最佳實踐。

寫好註釋是一種需要學習和發展的技能。為了練習寫註釋,可以考慮回頭將註釋新增到你以前的一些專案中。為了獲得靈感和看到最佳實踐,請檢視GitHub上記錄良好的Python專案。

評論留言