- Python編程實戰
- (美)李·沃恩
- 7955字
- 2021-07-09 10:37:26
1.1 項目1:生成假名
在此階段的熱身項目中,你將編寫一個把姓氏和名字隨機組合來產生虛假姓名的簡易Python程序。該程序將毫不費力地生成大量令人意想不到的假名。你還將學習編程規范的最佳實踐,以及在外部應用程序幫助下編寫符合這些規范的代碼。
《靈異妙探》的劇情跟你毫不相關嗎?你也可以用喜歡的姓名來替換代碼列表中的姓名。你可以輕而易舉地將此項目變成《權利的游戲》的姓名生成器,或者發現一個讓自己感到很驚喜的姓名“Benedict Cumberbatch”。對我來說,我最喜歡的姓名是“Bendylick Cricketbat”。
目標
編寫符合既定樣式的Python代碼,隨機生成一些有趣的姓名。
1.1.1 項目規劃與設計
制定項目計劃絕不是一件浪費時間的事。不管編程是出于樂趣,還是為了盈利,從某種程度上來說,你都需要十分精準地評估一些因素,諸如此項目的耗時、可能遇到的困難、完成此項工作所需的工具和資源等。要解決好這些問題,你首先需要明確自己在做什么。
一位成功的管理人士曾告訴我,他成功的秘訣就是不斷地向自己提出一些問題。例如,你在做怎樣的嘗試?你為什么要做這種嘗試?為什么要采用這種方式?耗費的時間和需要的資金分別是多少?厘清這些問題將有助于我們完成最終的項目設計,還能使這些問題的解決方案在我們的頭腦中呈現出清晰的脈絡。
艾倫·唐尼(Allen Downey)在他的編寫《像計算機科學家一樣思考Python(第2版)》中描述了兩種類型的軟件開發計劃:“原型和補丁(Prototype and Patch)”和“按計劃開發(Designed Development)”。在“原型和補丁”思想的指導下,先從一個簡單的程序開始,然后使用補丁和可編輯的代碼去解決測試過程中遇到的問題。在解決一個難以理解的復雜問題時,這不失為一個好辦法,但是這會產生復雜且不可靠的代碼。如果對問題本身有清晰的認識,并且知道如何去解決它,那么你就應該采用“按計劃開發”的軟件設計思想,盡量解決未來可能出現的問題,避免后續為程序添加補丁。這種方法可以使編寫的代碼更簡單和有效,而且通常也會使代碼變得更健壯和可靠。
對于本書中的每個項目,你都需要先清晰地理解其中的問題,明確項目目標,在此基礎上才開始編寫代碼。這樣一來,你就能夠更好地理解問題,制定開發計劃和設計策略。
1.1.2 策略
首先,定義兩個清單,它們分別用于存儲虛假的名字和姓氏。由于這兩個清單長度較短,它們不會占用大量內存,且不需要動態更新。在程序運行的過程中,這兩個列表應該也不會出現任何運行問題。因此,你可以用元組存儲名字和姓氏清單。
當程序運行后,它會根據這兩個元組存儲的元素,匹配姓氏和名字,生成一個新的姓名組合。用戶可以重復該過程,直到產生足夠多的虛假姓名為止。
在解釋器窗口中以某種方式突出顯示姓名,使它與命令提示信息有明顯的不同。IDLE提供的可用字體選項并不多,但是我們都知道錯誤信息會被標紅。在解釋器窗口中,默認的標準輸出函數是print(),但當加載sys模塊后,可以使用file參數將輸出重定向到錯誤信息輸出通道,使輸出的文字顏色為紅色:
print(something, file=sys.stderr).
最后,需要確定哪種編程風格是Python編程規范目前所推薦的。這些編程風格不僅約定了代碼的編寫規范,而且對嵌入在代碼內的文檔字符串(Docstring)也有具體的要求。
1.1.3 偽代碼
丘吉爾曾說過,“不要嘗試做你喜歡的事,要去喜歡你正在做的事”,你很難將編寫偽代碼與這句話聯系在一起,但這句話卻道出了人們使用偽代碼的心理過程。
偽代碼是一種使用任何結構化的人類語言對計算機程序執行過程進行解釋的高級非正式描述,它像是一種包含關鍵詞和適當縮進的簡單編程語言。程序開發者使用偽代碼的主要目的是忽略所有編程語言中的復雜語法,從而專注于程序的底層邏輯。盡管偽代碼被廣泛使用,但是目前只存在一些偽代碼使用方法的指導原則,而這些指導原則還沒有形成正式的標準。
如果編寫程序時受挫,那么主要原因是你沒有花時間去編寫偽代碼。對我來說,每當對編寫代碼感到困惑迷茫的時候,偽代碼總能給我新的啟發。因此,在本書的大多數項目中,你都會看到偽代碼的使用。至少,我希望你能看到偽代碼的實用價值,也希望你能養成在項目中使用偽代碼的習慣。
虛假姓名生成器程序的偽代碼描述如下:
定義名字元組 定義姓氏元組 從名字元組中隨機選擇一個名字 將這個名字分配給變量 從姓氏元組中隨機選擇一個姓氏 將這個姓氏分配給變量 在屏幕上用紅色字體按選擇的順序輸出姓名 詢問用戶是退出程序,還是重新開始 如果用戶選擇重新開始: 重復上述過程 如果用戶選擇退出: 結束并退出程序
如果不是只為了通過編程課程考核和向他人提供清晰的程序說明,那么請牢記使用偽代碼的目的。你不要認為這樣做是盲目服從(非標準的)編程規范,也不要將偽代碼的應用局限于編程,嘗試將它應用到更多的地方。一旦掌握了其應用竅門,你就會發現它可以幫助你完成其他任務,例如管理稅務、計劃投資、建造房子,甚至是準備野營。這是一種使思維集中的好方式,同時也能鍛煉你把編程思想移植到現實生活中的能力。
1.1.4 代碼
清單1-1是虛假姓名生成器程序pseudonyms.py,它根據已有的名字和姓氏元組生成假名,并輸出這個假名。如果不想將這些姓名全部輸入,你可以分別輸入它們的一個子集,也可以直接從配套資源中獲取這些假名數據。
清單1-1 根據名字和姓氏元組生成假名
pseudonyms.py
? import sys, random
? print("Welcome to the Psych 'Sidekick Name Picker.'\n")
print("A name just like Sean would pick for Gus:\n\n")
first = ('Baby Oil', 'Bad News', 'Big Burps', "Bill 'Beenie-Weenie'",
"Bob 'Stinkbug'", 'Bowel Noises', 'Boxelder', "Bud 'Lite' ",
'Butterbean', 'Buttermilk', 'Buttocks', 'Chad', 'Chesterfield',
'Chewy', 'Chigger", "Cinnabuns', 'Cleet', 'Cornbread', 'Crab Meat',
'Crapps', 'Dark Skies', 'Dennis Clawhammer', 'Dicman', 'Elphonso',
'Fancypants', 'Figgs', 'Foncy', 'Gootsy', 'Greasy Jim', 'Huckleberry',
'Huggy', 'Ignatious', 'Jimbo', "Joe 'Pottin Soil'", 'Johnny',
'Lemongrass', 'Lil Debil', 'Longbranch', '"Lunch Money"', 'Mergatroid',
'"Mr Peabody"', 'Oil-Can', 'Oinks', 'Old Scratch',
'Ovaltine', 'Pennywhistle', 'Pitchfork Ben', 'Potato Bug',
'Pushmeet','Rock Candy', 'Schlomo', 'Scratchensniff', 'Scut',
"Sid 'The Squirts'", 'Skidmark', 'Slaps', 'Snakes', 'Snoobs',
'Snorki', 'Soupcan Sam', 'Spitzitout', 'Squids', 'Stinky',
'Storyboard', 'Sweet Tea', 'TeeTee', 'Wheezy Joe',
"Winston 'Jazz Hands'", 'Worms')
last = ('Appleyard', 'Bigmeat', 'Bloominshine', 'Boogerbottom',
'Breedslovetrout', 'Butterbaugh', 'Clovenhoof', 'Clutterbuck',
'Cocktoasten', 'Endicott', 'Fewhairs', 'Gooberdapple', 'Goodensmith',
'Goodpasture', 'Guster', 'Henderson', 'Hooperbag', 'Hoosenater',
'Hootkins', 'Jefferson', 'Jenkins', 'Jingley-Schmidt', 'Johnson',
'Kingfish', 'Listenbee', "M'Bembo", 'McFadden', 'Moonshine', 'Nettles',
'Noseworthy', 'Olivetti', 'Outerbridge', 'Overpeck', 'Overturf',
'Oxhandler', 'Pealike', 'Pennywhistle', 'Peterson', 'Pieplow',
'Pinkerton', 'Porkins', 'Putney', 'Quakenbush', 'Rainwater',
'Rosenthal', 'Rubbins', 'Sackrider', 'Snuggleshine', 'Splern',
'Stevens', 'Stroganoff', 'Sugar-Gold', 'Swackhamer', 'Tippins',
'Turnipseed', 'Vinaigrette', 'Walkingstick', 'Wallbanger', 'Weewax',
'Weiners', 'Whipkey', 'Wigglesworth', 'Wimplesnatch', 'Winterkorn',
'Woolysocks')
? while True:
? firstName = random.choice(first)
? lastName = random.choice(last)
print("\n\n")
? print("{} {}".format(firstName, lastName), file=sys.stderr)
print("\n\n")
? try_again = input("\n\nTry again? (Press Enter else n to quit)\n")
if try_again.lower() == "n":
break
? input("\nPress Enter to exit.")
首先,向程序導入sys模塊和random模塊?。sys模塊使你能夠訪問具體的系統錯誤消息,同時允許你把IDLE窗口中的輸出文字設置為醒目的紅色。random模塊使你可以隨機地從存放名字和姓氏的元組中選擇數據項。
print語句的作用是向用戶介紹本程序的功能?。換行命令符\n強制開始新行;在字符串輸出的雙引號中,不必使用\轉義字符,而可以直接使用單引號’。需要注意的是,使用轉義字符將會降低代碼的可讀性。
接下來,分別定義名字和姓氏元組。然后,程序開始執行while循環?。將while循環語句的循環條件設置為True,即讓程序“一直運行,直到我讓你停下來為止”。最終,你會使用break語句來結束這個循環。
在while循環體內,先從first元組中隨機選擇一個名字,并把這個名字賦給firstName變量?。random模塊的choice()函數會隨機地從非空序列中選擇一個元素,并把該元素當作函數的返回值。就本例而言,非空序列指的是名字元組。
緊接著,從last元組中隨機選擇一個姓氏,并將它分配給lastName變量?。此時,你已經得到一組名字和姓氏,把它們輸出在shell窗口中。向print()函數提供可選參數file=sys.stderr?,使IDLE窗口中的“錯誤”信息顯示為紅色。同時,使用新的字符串格式化方法把姓名變量值轉換為字符串。需要注意的是,舊的字符串格式方法指的是使用操作符%將變量值轉換為字符串。在Python的官方網站可以獲得更多與新的字符串格式化方法有關的信息。
之后,程序生成的假名就會顯示出來。接著,利用input語句顯示一段提示信息,詢問用戶是再來一次,還是退出程序。為了使這個有趣的姓名在IDLE窗口中更加顯眼,本示例程序會使輸出結果之間包含一些空白行。對于這個請求,如果用戶直接按Enter鍵,那么變量try_again就不會捕捉到任何輸入內容?。由于沒有返回任何內容,因此if條件語句不成立,while循環會繼續運行,程序會再次輸出新的名字和姓氏對。如果用戶按N鍵,那么if語句中的條件成立,break語句會被執行。此時,while循環語句的判斷條件也不再是True,循環隨之結束。為了避免用戶不小心按下Caps lock鍵,利用字符串對象的lower()函數把用戶的輸入值轉換為小寫字符。換言之,用戶不必考慮輸入的是小寫字符還是大寫字符,程序會總是將它視為小寫。
最后,程序顯示一條提示信息,告訴用戶按Enter鍵結束程序?。當用戶按Enter鍵時,input()函數不會把返回值賦給任何變量,程序結束,同時控制臺窗口關閉。在IDLE編輯器窗口中,按F5鍵將會執行程序。
這段代碼可以正常運行,但是僅能正常運行是不夠的,Python程序還得合乎一定的編程規范。
1.Python社區的編程規范
根據Python之禪(The Zen of Python)的說法,“做好一件事情的方法應該有且只有一種”。在實踐的基礎上,Python社區不斷推出新的編程指導原則,發布新的Python增強提議(Python Enhancement Proposals,PEP),這些提議涉及一系列編程規范。Python發行版中的標準庫也遵循相關編程規范。PEP 8是這些增強提議中最重要的編程規范。新的編程規范不斷涌現,而舊的編程規范隨著語言的改變逐漸被淘汰,PEP 8標準也隨著時間的推移而不斷演化。
PEP 8標準不僅約定了Python中標識符的命名原則,還規定了空白行、制表符和空格的使用方式,以及每行允許的最大字符長度和可采用的注釋方式。PEP 8標準能提高代碼的可讀性,使所有的Python程序在編程規范上保持一致。當開始用Python編寫程序時,你應該努力學習這些公認的編程規范,并養成遵守這些規范的良好習慣。本書的代碼樣式將與PEP 8標準保持一致,但是為了滿足出版行業的排版要求,我在撰寫本書時并沒有嚴格遵守編程規范(例如,在本書中我會盡量減少代碼注釋和空行,也會讓文檔字符串盡可能地短)。
在跨職能團隊中,標準化的名稱和過程對程序的開發尤為重要。否則,科學家和工程師之間可能會產生很多誤解。1999年,由于不同的團隊使用不同的測量單位,工程師們失去了對火星氣候軌道飛行器(Mars Climate Orbiter)的控制。在過去的20年時間里,我建立了能夠應用于工程上的地球計算機模型。工程師可以使用腳本將這些模型加載到專門的軟件中。為了幫助那些沒有經驗的人提高效率,工程師們會在項目開發過程中共享這些腳本。由于這些“命令文件”是根據每個項目定制的,因此在模型更新期間,工程師會對屬性名的更改感到惱火。實際上,他們的內部準則之一便是“要求建模者使用一致的屬性名”。
2.使用Pylint模塊檢查代碼
盡管你已經熟悉PEP 8標準,但是仍然可能會犯錯誤。查看代碼是否遵守PEP 8標準也是一件很麻煩的事情。幸運的是,你有許多工具可用,例如Pylint、pycodestyle和Flake8。在這些工具的幫助下,你可以輕松地編寫出遵循PEP 8標準的代碼。對于本章中的這個項目,你可以使用Pylint模塊檢查其代碼的規范性。
(1)安裝Pylint模塊
Pylint模塊是一款Python的源代碼錯誤和代碼質量檢查器。在Pylint模塊官網上,你可以找到該模塊安裝包的免費副本;根據所使用的操作系統,找到Install按鈕。這個按鈕將顯示安裝Pylint模塊的命令。例如,在Windows操作系統上進入Python的安裝主目錄(如C:\Python35),在主目錄中按住Shift鍵并單擊鼠標右鍵,打開上下文菜單,根據你所使用的Windows版本,選擇“在此處打開PowerShell窗口”(open PowerShell window here)選項。最后,在彈出的窗口中執行pip install pylint命令。
(2)運行Pylint模塊
在Windows操作系統中,在命令行窗口中可以運行Pylint模塊。而對于較新的操作系統,也可以在PowerShell(在待檢查的Python模塊主目錄中,按住Shift并單擊鼠標右鍵即可打開它)中運行它。輸入pylint filename就可以運行該程序,如圖1-1所示。擴展名.py是可選的,需要注意的是,實際的目錄路徑可能與圖中顯示的有所不同。在macOS和類UNIX操作系統上可以使用終端模擬器來執行這些操作。
圖1-1 在Windows操作系統的命令行窗口中運行Pylint模塊
Pylint模塊把程序的檢查結果顯示在命令行窗口中。下面是一個Pylint模塊的輸出示例:
C:\Python35\Python 3 Stuff\Psych>pylint pseudonyms.py No config file found, using default configuration ************* Module pseudonyms C: 45, 0: No space allowed around keyword argument assignment print(firstName, lastName, file = sys.stderr) ^ (bad-whitespace) C: 1, 0: Missing module docstring (missing-docstring) C: 2, 0: Multiple imports on one line (sys, random) (multiple-imports) C: 7, 0: Invalid constant name "first" (invalid-name) C: 23, 0: Invalid constant name "last" (invalid-name) C: 40, 4: Invalid constant name "firstName" (invalid-name) C: 42, 4: Invalid constant name "lastName" (invalid-name) C: 48, 4: Invalid constant name "try_again" (invalid-name)
每行開頭的大寫字母代表消息碼。例如,“C:15, 0”指的是第15行第0列違背Python編程規范。下面是一些常見的Pylint模塊消息碼:
R:違反“良好實踐”原則。
C:違反編程規范。
W:不嚴重的編程問題。
E:嚴重的編程問題(可能是一個錯誤)。
F:致命錯誤,阻止Pylint模塊進一步運行。
通過與PEP 8標準進行一致性對比,Pylint模塊會為你的代碼打分。在這個例子中,代碼的得分為4(滿分10分):
Global evaluation ----------------- Your code has been rated at 4.00/10 (previous run: 4.00/10, +0.00)
(3)處理常量名稱錯誤
你可能已經注意到,Pylint模塊錯誤地假設全局代碼空間中的所有變量都表示常量,因此它們必須全部使用大寫。該問題的解決方法有許多。第一種方法就是將這些變量放入main()函數中,如清單1-2所示。這樣一來,這些常量就不再位于全局代碼空間。代碼如下:
清單1-2 main()函數的定義和調用方式
def main(): some indented code some indented code some indented code ? if __name__ == "__main__": ? main()
變量__name__是一種特殊的內置變量,你可以用它判斷程序的運行方式,即程序是獨立運行的,還是以導入其他程序中的方式運行的。需要注意的是,導入模塊指的是在一個Python程序內使用另一個Python程序的行為。如果直接運行該程序,變量__name__就會被設置為“__main__”。在清單1-2中,變量__name__的作用就是確保當該腳本以模塊的形式導入其他程序時,main()函數不會被調用。只有當直接運行該腳本時,if語句的判斷條件才成立?,main()函數才會被調用?。但你并非總要遵守這樣的約定。例如,若代碼中僅有一個函數,就不需要在代碼中使用變量__name__,直接以模塊的形式將它導入另一個調用它的模塊中即可。
除import語句之外,我們把程序pseudonyms.py的所有代碼都放到main()函數中,在if語句內調用main()函數,如清單1-2所示。你既可以手動修改程序,使程序pseudonyms.py的代碼滿足前面所述的編程規范,也可以從本書配套資源中下載對應的程序pseudonyms_main.py。然后重新運行Pylint模塊,檢查修改后的程序。你會在命令行窗口中看到下面的輸出結果:
C:\Python35\Python 3 Stuff\Psych>pylint pseudonyms_main No config file found, using default configuration ************* Module pseudonyms_main C: 47, 0: No space allowed around keyword argument assignment print(firstName, lastName, file = sys.stderr) ^ (bad-whitespace) C: 1, 0: Missing module docstring (missing-docstring) C: 2, 0: Multiple imports on one line (sys, random) (multiple-imports) C: 4, 0: Missing function docstring (missing-docstring) C: 42, 8: Invalid variable name "firstName" (invalid-name) C: 44, 8: Invalid variable name "lastName" (invalid-name)
現在,那些令人討厭的無效常量名稱提示已經消失,但是你的代碼依然沒有完全遵守PEP 8標準。盡管我很喜歡使用像firstName這樣的駝峰命名法,但是Python規范不允許我這樣做。
(4)配置Pylint模塊
當使用Pylint模塊檢查較短的腳本時,我更傾向于使用Pylint模塊的默認設置,并忽略掉“無效常量名稱”提示。我還喜歡使用-rn(-reports=n的簡寫)選項,它會阻止Pylint模塊返回大量無關的統計信息:
C:\Python35\Python 3 Stuff\Psych>pylint -rn pseudonyms_main.py
注意,-rn選項會禁用Pylint模塊的代碼評分功能。
當使用Pylint模塊時,經常遇到的另外一個問題是:它的默認最大行長為100個字符,但是,PEP 8建議的最多字符個數為79。若想與PEP 8保持一致,請用下面所示的設置運行Pylint模塊:
C:\Python35\Python 3 Stuff\Psych>pylint --max-line-length=79 pseudonyms_main
此時,你會看到縮減最大行長后,main()函數內某些行的長度超出規定值:
C: 12, 0: Line too long (80/79) (line-too-long) C: 14, 0: Line too long (83/79) (line-too-long) --snip--
當運行Pylint模塊時,你不必每次都手動輸入這些選項和參數。你可以使用該模塊的--generate-rcfile命令生成自定義的配置文件。例如,為了避免輸出大量的統計信息,將最大行長設置為79個字符,在命令行窗口中輸入如下內容,即可生成所需的配置文件:
your pathname>pylint -rn --max-line-length=79 --generate-rcfile > name.pylintrc
將自定義參數設置放在--generate-rcfile > name.pylintrc命令之前,在擴展名.pylintrc的前面輸入配置文件名。你可以像前面所做的那樣,生成一個獨立的配置文件來評估Python程序的規范性。當生成配置文件時,Pylint模塊允許設置配置文件的存儲路徑,但是默認情況下,它會自動保存在當前的工作目錄中。
為了使用自定義的配置文件,你需要在待檢查程序前輸入自定義配置文件名,并在配置文件名前輸入--rcfile。例如,若要在文件myconfig.pylintrc指定的配置下運行pseudonyms_main.py程序,則需要在命令行窗口中輸入如下內容:
C:\Python35\Python 3 Stuff\Psych>pylint --rcfile myconfig.pylintrc pseudonyms_main
3.使用文檔字符串描述代碼
Pylint模塊檢測出程序pseudonyms_main.py缺少文檔字符串。PEP 257標準指出:文檔字符串是一種常放在模塊、函數、類和方法定義開頭的字符串。文檔字符串的作用是簡要地描述代碼的功能,它可能會包括諸如輸入要求等在內的說明信息。下面是一個在函數中使用單行文檔字符串的示例,該字符串在一對三引號內:
def circ(r): """Return the circumference of a circle with radius of r.""" c = 2 * r * math.pi return c
上面的文檔字符串只是為了說明函數的功能,在實際的應用中,文檔字符串可能更長,包含的信息也更多。例如,下面是這個函數的多行文檔字符串示例,該字符串包含函數的輸入和輸出參數說明等信息:
def circ(r): """Return the circumference of a circle with radius of r. Arguments: r – radius of circle Returns: float: circumference of circle """ c = 2 * r * math.pi return c
文檔字符串的書寫方式會因個人、項目和公司的不同而有所差別。因此,你會發現存在很多相互矛盾的規范。谷歌公司就有獨具該公司特色的編程規范??茖W界的某些人士喜歡使用NumPy文檔字符串書寫標準。reStructuresText是一種流行的文檔字符串格式化工具,它主要與工具Sphinx結合使用。通過Python代碼的文檔字符串,這些工具可為項目生成HTML和PDF格式的文檔。如果閱讀過一些Python模塊的字符串文檔,你可能看到過Sphinx字符串文檔格式工具的使用。在1.11節中,你可以學到一些不同風格的文檔字符串編寫規范。
利用一款名為pydocstring的免費工具可以檢查文檔字符串是否符合PEP 257標準。若想把這款工具安裝在Windows操作系統和任何其他操作系統上,你可以打開命令行窗口并執行pip install pydocstyle命令(如果操作系統中既安裝有Python2,又安裝有Python3,那么安裝該工具時,你要在命令行窗口中輸入pip3)。
為了使用pydocstring工具,先打開命令行窗口,將當前工作目錄切換至待檢查代碼所在的目錄。如果在命令行窗口中未指定文件名,pydocstring工具會檢查該目錄中的所有Python程序,并為每個程序生成相應的檢查報告:
C:\Python35\Python 3 Stuff\Psych>pydocstyle .\OLD_pseudonyms_main.py:1 at module level: D100: Missing docstring in public module .\OLD_pseudonyms_main.py:4 in public function `main`: D103: Missing docstring in public function .\ pseudonyms.py:1 at module level: D100: Missing docstring in public module .\ pseudonyms_main_broken.py:1 at module level: D200: Oneline docstring should fit on one line with quotes (found 2) .\ pseudonyms_main_broken.py:6 in public function `main`: D205: 1 blank line required between summary line and description (found 0)
如果程序的文檔字符串滿足Python編程規范,那么pydocstring工具不會返回任何內容:
C:\Python35\Python 3 Stuff\Psych>pydocstyle pseudonyms_main_fixed.py C:\Python35\Python 3 Stuff\Psych>
對于本書的所有項目,我將會在項目代碼中使用一些簡單的文檔字符串,盡量降低注釋的使用頻率,避免過多注釋影響代碼的可讀性。當然,若想練習文檔字符串的編寫方法,你可以對前面的示例進行隨意拓展,也可以使用pydocstring工具來檢查文檔字符串的規范性。
4.檢查代碼風格
下面來了解一下如何使虛假姓名生成器程序的代碼更符合PEP 8和PEP 257標準。
將程序pseudonyms_main.py復制一份,把它重命名為pseudonyms_main_fixed.py,使用Pylint模塊對它的規范性進行評估:
your_path>pylint --max-line-length=79 pseudonyms_main_fixed
不要使用-rn選項,否則會禁用評分功能。在命令行窗口的底部,你會看到如下輸出信息:
Global evaluation ----------------- Your code has been rated at 3.33/10
現在,根據Pylint模塊的檢查結果修改程序pseudonyms_main_fixed.py的代碼。在下面的例子中,我已經用粗體標注了要更正的地方。為了解決最大行長度不一致引起的問題,我修改了元組的名稱。在本書的配套資源中,你可以找到修改后的代碼對應的程序pseudonyms_ main_fixed.py。
pseudonyms_main_fixed.py
"""從兩個獨立的名字元組中隨機選擇元素來生成有趣的假名"""
import sys
import random
def main():
"""從兩個名字元組中隨機選擇一些名字并輸出到屏幕上"""
print("Welcome to the Psych 'Sidekick Name Picker.'\n")
print("A name just like Sean would pick for Gus:\n\n")
first = ('Baby Oil', 'Bad News', 'Big Burps', "Bill 'Beenie-Weenie'",
"Bob 'Stinkbug'", 'Bowel Noises', 'Boxelder', "Bud 'Lite'",
'Butterbean', 'Buttermilk', 'Buttocks', 'Chad', 'Chesterfield',
'Chewy', 'Chigger', 'Cinnabuns', 'Cleet', 'Cornbread',
'Crab Meat', 'Crapps', 'Dark Skies', 'Dennis Clawhammer',
'Dicman', 'Elphonso', 'Fancypants', 'Figgs', 'Foncy', 'Gootsy',
'Greasy Jim', 'Huckleberry', 'Huggy', 'Ignatious', 'Jimbo',
"Joe 'Pottin Soil'", 'Johnny', 'Lemongrass', 'Lil Debil',
'Longbranch', '"Lunch Money"', 'Mergatroid', '"Mr Peabody"',
'Oil-Can', 'Oinks', 'Old Scratch', 'Ovaltine', 'Pennywhistle',
'Pitchfork Ben', 'Potato Bug', 'Pushmeet', 'Rock Candy',
'Schlomo', 'Scratchensniff', 'Scut', "Sid 'The Squirts'",
'Skidmark', 'Slaps', 'Snakes', 'Snoobs', 'Snorki', 'Soupcan Sam',
'Spitzitout', 'Squids', 'Stinky', 'Storyboard', 'Sweet Tea',
'TeeTee', 'Wheezy Joe', "Winston 'Jazz Hands'", 'Worms')
last = ('Appleyard', 'Bigmeat', 'Bloominshine', 'Boogerbottom',
'Breedslovetrout', 'Butterbaugh', 'Clovenhoof', 'Clutterbuck',
'Cocktoasten', 'Endicott', 'Fewhairs', 'Gooberdapple',
'Goodensmith', 'Goodpasture', 'Guster', 'Henderson', 'Hooperbag',
'Hoosenater', 'Hootkins', 'Jefferson', 'Jenkins',
'Jingley-Schmidt', 'Johnson', 'Kingfish', 'Listenbee', "M'Bembo",
'McFadden', 'Moonshine', 'Nettles', 'Noseworthy', 'Olivetti',
'Outerbridge', 'Overpeck', 'Overturf', 'Oxhandler', 'Pealike',
'Pennywhistle', 'Peterson', 'Pieplow', 'Pinkerton', 'Porkins',
'Putney', 'Quakenbush', 'Rainwater', 'Rosenthal', 'Rubbins',
'Sackrider', 'Snuggleshine', 'Splern', 'Stevens', 'Stroganoff',
'Sugar-Gold', 'Swackhamer', 'Tippins', 'Turnipseed',
'Vinaigrette', 'Walkingstick', 'Wallbanger', 'Weewax', 'Weiners',
'Whipkey', 'Wigglesworth', 'Wimplesnatch', 'Winterkorn',
'Woolysocks')
while True:
first_name = random.choice(first)
last_name = random.choice(last)
print("\n\n")
# 使用“致命錯誤”字體設置,在IDLE窗口中將輸出的姓名顏色設為紅色
print("{} {}".format(first_name, last_name), file=sys.stderr)
print("\n\n")
try_again = input("\n\nTry again? (Press Enter else n to quit)\n ")
if try_again.lower() == "n":
break
input("\nPress Enter to exit.")
if __name__ == "__main__":
main()
在滿分為10分的情況下,Pylint模塊給修改后的程序代碼打了10分:
Global evaluation ----------------- Your code has been rated at 10.00/10 (previous run: 3.33/10, +6.67)
從前面的內容可以看到,當評估程序pseudonyms_main_fix .py時,pydocstyle工具沒有產生錯誤信息。但是,不要錯誤地認為程序的編程規范良好,甚至認為它已經足夠好。例如,下面的文檔字符串也可以通過pydocstyle工具的檢查:
"""ksjkdls lskjds kjs jdi wllk sijkljs dsdw noiu sss."""
編寫簡潔且真正有用的文檔字符串和注釋是一件很困難的事情。我們可以借助PEP 257標準來處理文檔字符串,但是注釋的樣式通常比較靈活,適用范圍也相對更為開放。注釋太多會產生視覺干擾,從而導致用戶反感。過多的注釋是不必要的,良好的代碼本身就是編寫思路的自述。開發者添加注釋的原因有很多,如澄清代碼意圖,避免用戶使用程序時出現潛在的錯誤;提醒用戶注意輸入數據的度量單位或格式等。若想正確地使用注釋,則需要關注別人使用注釋的方式,借鑒那些好的注釋例子。此外,你還要考慮5年后重新閱讀自己的代碼時,希望在注釋中看到什么內容。
Pylint模塊和pydocstyle工具都易于安裝和運行,它們可以幫助你更好地學習并遵守Python社區公認的編程標準。當你通過Web論壇尋求幫助,并希望獲得友好、溫和的回答時,你應該遵循的一個原則就是:在代碼發布到論壇之前,先運行Pylint模塊,評估代碼的規范性。
- JavaScript修煉之道
- Python 深度學習
- Magento 2 Theme Design(Second Edition)
- Arduino開發實戰指南:LabVIEW卷
- Object-Oriented JavaScript(Second Edition)
- The Data Visualization Workshop
- OpenMP核心技術指南
- IoT Projects with Bluetooth Low Energy
- Node.js區塊鏈開發
- Hands-On Dependency Injection in Go
- SFML Game Development
- Python Penetration Testing Essentials
- Ubuntu Server Cookbook
- ASP.NET本質論
- Linux Networking Cookbook