按照《代碼整潔之道》的說法,“花在閱讀和編碼上的時間比遠遠超過 10:1。”
通常,當我們在學校學習時,編程美學不是一個關鍵問題。用 Python 寫代碼時,個人也會遵循自己的風格。然而,當我們必須花大把時間來理解一個人的隱式代碼時,這項工作肯定不受歡迎,這種情況同樣可能發生在別人閱讀我們的代碼時。所以,讓我們聚焦 Python 之禪和一些改進技巧,從而解決問題。
1. Python 之禪?
對於此前沒聽說過的人,請在 Python 解釋器中鍵入並執行import this,會出現由 Tim Peters 撰寫的 19 條指導原則:
- 優美勝於醜陋;
- 明瞭勝於晦澀;
- 簡單勝於複雜;
- 複雜勝於晦澀;
- 扁平勝於嵌套;
- 間隔勝於緊湊;
- 可讀性很重要;
- 特例不足以特殊到違背這些原則;
- 實用性勝過純粹;
- 永遠不要默默地忽視錯誤;
- 除非明確需要這樣做;
- 面對模稜兩可,拒絕猜測;
- 解決問題最直接的方法應該有一種,最好只有一種;
- 當然這是沒法一蹴而就的,除非你是荷蘭人;
- 做也許好過不做;
- 但不想就做還不如不做;
- 如果方案難以描述明白,那麼一定是個糟糕的方案;
- 如果實現容易描述,那可能是個好方案;
- 命名空間是一種絕妙的理念,多加利用!
在這篇文章中,我將分享自己對這些格言的理解以及我學到的一些有用的 Python 技巧。
2. 優美勝於醜陋
Python 具有語法簡單、代碼可讀性強和命令類似英語等特點,這讓編寫 Python 代碼比使用其他編程語言更容易、更高效。例如,使用or and和|| &&構建語義相同的表達式:
<code># &&, || if a == 0 && b == 1 || c == True: # and, or if a == 0 and b == 1 or c == True: # 這兩個邏輯表達式在 Python 中是相同的 # 從語義的角度來看,可以使用選擇操作符來構造完全相同的表達式。 /<code>
此外,代碼的佈局和組成非常重要,有大量資源涉及這個主題。下面是最受歡迎也是我最喜歡的一個:PEP 8——Python 代碼風格指南。
https://www.python.org/dev/peps/pep-0008/
瀏覽完 PEP8 後,看看下面這些文章,其中展示了一些亮點和應用:
- 如何參照 PEP 8 編寫漂亮的 Python 代碼
https://realpython.com/python-pep8/
- 優雅的 Python 與 PEP8
https://medium.com/@mariasurmenok/stylish-python-with-pep8-c3ca93531418
- PEP-8 的陷阱
https://medium.com/@ian.reinert/the-pitfalls-of-pep-8-b6108b006ed9
永遠不要弄亂你的代碼。要優雅而美麗。
3. 明瞭勝於晦澀
在 Python 中,良好的命名約定不僅可以提升你的課堂成績,而且還能讓你的代碼更明瞭。幸運的是,你能在 PEP8 中找到一些指導原則,我想在下面強調其中的一些要點。
https://www.python.org/dev/peps/pep-0008/
- 一般來說,避免使用以下名稱:
- 太寬泛,如my_list;
- 太冗長,如list_of_machine_learning_data_set;
- 太模糊,如“1”、“I”、“o”、“O”。
- 包 / 模塊名應該全部小寫:
- 首選使用一個單詞命名;
- 當需要使用多個單詞時,使用下劃線分割它們。
- 類名應遵循 UpperCaseCamelCase 規範
- 變量\\方法\\函數應該採用小寫(如果需要,用下劃線分割)
- 常量名必須全大寫(如果需要,用下劃線分割)
一切都必須清晰易懂。
4. 簡單勝於複雜
簡單比複雜更難:你必須付出巨大艱辛,化繁為簡。但這一切到最後都是值得的,因為一旦你做到了,你便能創造奇蹟。——喬布斯
很多時候,在處理迭代器時,我們還需要保存迭代計數。Python 通過提供一個名為enumerate()的內置函數簡化這一任務。以下是一種不成熟的方法,然後是推薦方法:
<code>words = ['Hannibal', 'Hanny', 'Steeve'] # 不成熟的方法 index = 0 for word in words: print(index, word) index += 1 # 推薦方法 for index, word in enumerate(words): print(index, word) /<code>
另一個示例是使用內置的zip()函數,該函數創建一個迭代器,對來自兩個或多個迭代器的元素進行配對。你可以使用它來快速有效地解決常見的編程問題,比如創建字典。
<code>subjects = ['math', 'chemistry', 'biology', 'pyhsics'] grades = ['100', '83', '90', '92'] grades_dict = dict(zip(subjects, grades)) print(grades_dict) /<code>
化繁為簡的能力就是消除不必要的東西,保留必要的東西。
5. 複雜勝於晦澀
複雜(complex )和晦澀(complicated )的區別在於,複雜是指組件的系統層級,晦澀是指難度高。
有時候,儘管我們試圖讓任務變得簡單和傻瓜化,結果可能仍然很糟。
在這種情況下,編程優化變得很有必要,我最喜歡的學習方法是完成 coding challenge websites 上的工作。你可以查看其他人的解決方案,甚至能受到更好算法的啟發。
https://www.freecodecamp.org/news/the-10-most-popular-coding-challenge-websites-of-2016-fb8a5672d22f/
對於入門,HackerRank 提供了適合新手程序員的各種級別任務,這非常棒。之後,可以去嘗試更專業的網站,比如 Coderbyte 和 Topcoder。
6. 扁平勝於嵌套
嵌套模塊在 Python 中並不常見——至少我之前沒有見過像module.class.subclass.function這樣的東西——可讀性不好。雖然在另一個子模塊中構建子模塊可能會減少代碼行數,但我們不希望用戶被不直觀的語法所困擾。
7. 間隔勝於緊湊
不要在一行中插入太多代碼,這會給讀者帶來壓力。建議最大行長度 79 個字符。這樣,當使用代碼評審工具時,編輯器窗口寬度限制才能很好工作。
使用 Python 從 Unsplash 下載圖片
8. 可讀性很重要
代碼的閱讀次數比編寫次數多。考慮下縮進,它讓代碼更容易閱讀,比較下面的代碼:
<code>money = 10000000 print("I earn", money, "dollars by writing on medium.") money = 10_000_000 print(f"I earn {money} dollars by writing on medium.") /<code>
在本例中,代碼結果相同,但是後一段代碼通過使用下劃線佔位符和 f-string 提供了更好的可讀性。在 Python 3.6 發佈後,f-string 開始讓格式化變得更簡單,並且在處理包含更多變量的更長的句子時更強大。
一個作家的風格不應該在他的思想和讀者的思想間設置障礙。
9. 特例不足以特殊到違背這些原則
關鍵是為一般情況提供一貫支持,嘗試將一個繁瑣的項目重新組織成一個簡單形式。例如,根據其功能,結構化類的代碼或將其分類到不同的文件中,即使 Python 並不強迫你這樣做。由於 Python 是一種多範式編程語言,解決問題的一個強大方法是創建對象,這就是所謂的面向對象編程。
面向對象編程是一種組織程序結構的編程範式,讓屬性和行為可以被看作是單獨對象。它的優點是直觀和易於操作,許多教程都很好地解釋了這些概念。
10. 實用性勝過純粹
這句格言與前一句相矛盾,它提醒我們保持它們之間的平衡
11. 永遠不要默默地忽視錯誤
放過錯誤最終會留下隱式 Bug,並且這些 Bug 更難被發現。Python 提供了健壯的錯誤處理,與其他語言相比,程序員使用該工具並不難。
<code>try: x = int(input("Please enter an Integer: ")) except ValueError: print("Oops! This is not an Integer.") except Exception as err: print(err) else: print('You did it! Great job!') finally: print('ヽ(✿゚▽゚)ノ') # 1. 這段代碼可能中斷。 # 2. 如果出現值錯誤就會觸發。 # 3. 處理值錯誤之外的錯誤。 # 4. 如果沒有觸發錯誤就執行。 # 5. 不管是否觸發錯誤都執行。 /<code>
根據 Python 文檔:“即使一個語句或表達式在語法上是正確的,在試圖執行它時也可能會導致錯誤。”特別是對於大型項目,我們不希望在耗時的計算後,代碼崩潰。這就是異常管理的魅力所在。
12. 除非明確需要這樣做
在某些情況下,小錯誤不會困擾你。不過,也許你想捕獲特定錯誤。要獲得關於特定錯誤消息的更多細節,我建議閱讀官方的內置異常文檔並找到你需要的內容。
https://docs.python.org/3/library/exceptions.html
13. 面對模稜兩可,拒絕猜測
重要的是要不斷學習,享受挑戰,容忍歧義。我們都不知道最終會怎樣。——瑪蒂娜·霍納
這句話優雅而抒情,但在編程中不是一個好的隱喻。歧義可能是指不清楚的語法、複雜的程序結構或觸發錯誤消息的錯誤。例如,第一次使用numpy模塊時的一個簡單錯誤:
<code>import numpy as np a = np.arange(5) print(a /<code>
ValueError: 具有多個元素的數組的真值不明確,請使用 a.any() 或 a.all()
如果執行上面代碼,你將在輸出中發現一個由 5 個布爾值組成的數組,表明值在 3 以下。因此,if語句不可能確定狀態。消息中顯示的內置函數.all() 和.any()用於代替 And/Or。
<code>import numpy as np a = np.array([True, True, True]) b = np.array([False, True, True]) c = np.array([False, False, False]) print(a.all()) print(a.any()) print(b.all()) print(b.any()) print(c.all()) print(c.any()) /<code>
輸出表明,.all()僅在所有項都為True時才返回True,而.any()在有一項為True時就返回True。
14. 解決問題最直接的方法應該有一種,最好只有一種
想想為什麼 Python 被描述為一種易於學習的編程語言。Python 具有非凡的內置函數 / 庫和高度的可擴展性,它鼓勵程序員優雅地編寫代碼。儘管有更多的解決方案可以提供靈活性,但對於同一個問題,它們可能會花費更多時間。
15. 當然這是沒法一蹴而就的,除非你是荷蘭人
Python 之父 Guido van Rossum 是一位荷蘭程序員,他讓這句格言變得無可爭議。你不會聲稱自己比他更瞭解 Python……至少我不會。
16. 做也許好過不做
你可以拖延,但時間不會,失去的時間一去不復返。——本傑明·富蘭克林
對於那些像我一樣患有拖延症,正在尋求改變的人,看看這個,和恐慌怪獸合作。
另一方面,這個格言的另一個方面是阻止你過度計劃,這並不比看 Netflix 更有效率。
拖延和過度計劃的共同特徵就是“什麼都做不了。”
17. 不想就做還不如不做
“做也許好過不做”並不意味著計劃沒用。把你的想法寫下來,設定一個要征服的目標,比不想就做要好。
例如,我通常在每個星期天花一個小時來制定我的周計劃,並在睡覺前更新我明天的計劃,看看有什麼需要推遲的事情。
18. 如果解決方案難以解釋清楚,那一定很糟糕
回想一下“複雜勝於晦澀”的理念。通常,晦澀的代碼意味著弱設計,特別是在像 Python 這樣的高級編程語言中。
然而,在某些情況下,其領域知識的複雜性可能會讓實現難以解釋,而如何優化讓其明晰易懂至關重要。這裡有一個規劃項目指南,可以給你提供幫助。
https://docs.python-guide.org/writing/structure/
19. 如果實現容易描述,那可能是個好方案
使設計(甚至人們的生活)更容易,即使背景知識可能很深刻,這是編程的專業知識,我認為也是編程中最困難的部分。
利用 Python 的簡單性和可讀性來實現一些瘋狂的想法。
20. 命名空間是一種絕妙的理念,多加利用!
最後但同樣重要的是,命名空間是一組符號,用於組織各種對象,以便這些對象可以通過惟一的名稱引用。在 Python 中,命名空間是由以下元素組成的系統:
- 內置命名空間:可以在不創建自定義函數或導入模塊(如print()函數)的情況下調用。
- 全局命名空間:當用戶創建一個類或函數時,將創建一個全局命名空間。
- 局部命名空間:局部作用域中的命名空間。
命名空間關係圖
命名空間系統可以防止 Python 模塊名稱之間產生衝突。
最後,小編想說:我是一名python開發工程師,
整理了一套最新的python系統學習教程,
想要這些資料的可以關注私信小編“01”即可(免費分享哦)希望能對你有所幫助
閱讀更多 Python智禪 的文章