天天看點

如何寫出更具有Python風格的代碼

我們都喜歡 Python,因為它讓程式設計和了解變的更為簡單。但是一不小心,我們就會忽略規則,以非 Pythonic 方式編寫一堆垃圾代碼,進而浪費 Python 這個出色的語言賦予我們的優雅。Python 的代碼風格是非常優雅、明确和簡單,在 Python 解釋器中執行 <code>import this</code> 你可以看到 Tim Peters 編寫的 Python 之禅:

這裡我找了目前最好的中文版本:

美 優于 醜

明确 優于 隐晦

簡單 優于 複雜

複雜 也好過 繁複

扁平 優于 嵌套

稀疏 優于 擁擠

可讀性很重要

固然代碼實用與否 比潔癖更重要,

我們以為的特例也往往沒有特殊到必須打破上述規則的程度

除非刻意地靜默,否則不要無故忽視異常

如果遇到模棱兩可的邏輯,請不要自作聰明地瞎猜。

應該提供一種,且最好隻提供一種,一目了然的解決方案

當然這是沒法一蹴而就的,除非你是荷蘭人[1]

固然,立刻着手 好過 永遠不做。

然而,永遠不做 也好過 不審慎思考一撸袖子就莽着幹

如果你的實作很難解釋,它就一定不是個好主意

即使你的實作簡單到爆,它也有可能是個好辦法

命名空間大法好,不搞不是地球人!

[1]:本文作者 Tim peters 解釋說這裡的荷蘭人指的是 Python 的作者 Guido van Rossum.

以下是用 Python 編寫更好的代碼的 8 種方法:

如果需要列印清單中的所有元素及其索引,你想到的第一件事是:

那麼你仍然在編寫 C 代碼。擺脫這一點,請牢記 Python 關鍵字 enumerate 。它索引清單/字元串中的所有元素,并且支援設定索引的起始編号:

現在看起來更好了,而且更加 Pythonic。将清單轉換成字元串呢?如果你這樣寫:

就是 C 風格,如果使用 Python 的關鍵字 join,不僅效率更高,而且更優雅:

就像 join 一樣  ,Python 有很多神奇的關鍵字,是以請不要為語言工作,而是使用該語言為你工作。

如何寫出更具有Python風格的代碼

我不是要求你完全遵循 PEP8,而是要求遵循其中的大多數規則,何況現在有很多自動格式化的工具,足以讓你的代碼更加美觀,我們的 Python 之父也說過:閱讀代碼的頻率遠遠高于寫代碼的頻率,他是如此的正确!是以代碼的可讀性非常重要。

你是否對自己曾經寫過的代碼感到好奇?為什麼這麼寫,這句話為什麼在這?好吧,PEP8 是大多數這類問題的答案。盡管代碼注釋是個好方法,但是代碼的風格也需要加以調整,比如變量 i , j , count 等即使第一次出現時寫了注釋,也不能保證後面你仍然記得住,這樣來看就浪費了寶貴的時間。

任何普通的程式員都可以編寫計算機可以了解的代碼。隻有好的程式員可以編寫人類可以了解的代碼。
如何寫出更具有Python風格的代碼

首選 CamelCase 作為類, UPPER_WITH_UNDERSCORES 作為常量,而 lower_with_underscores 作為變量,方法和子產品名稱。即使使用,也要避免使用單一名稱功能 lambda 。

常用的推導式有:清單推導式,集合推導式,字典推導式。先說下清單推導式。

清單推導式就是當我們需要基于一個已有的清單建立新的清單時,所使用的文法格式,清單推導式包含以下四個部分:

1、一個輸入序列(Input Sequence) 2、一個變量,代表着輸入序列的一個成員(Variable) 3、一個可選的判定表達式,表達這個變量滿足的條件(Optional Predicate ) 4、一個輸出序列,根據 2 和 3 生成一個輸出序列(Output Expression)

比如有個清單既有數字,又有字元,現在需要計算數字的平方,并将結果放在新的清單中,如果不用清單推導式,寫出的代碼就是這樣的:

如果使用清單推導式,隻需要兩行代碼,非常的優雅:

如何寫出更具有Python風格的代碼

當然,如果你喜歡 map 和 filter,你還可以這樣做,當時這是不推薦的,因為可讀性不好:

比如集合推導式的使用:

給定輸入

希望得到:

那麼集合推導式就是:

再比如字典推導式:

從上面可以看出。推導式風格的代碼是優雅的,人類易讀的。

如果你在寫代碼時仍然在顯式的關閉檔案,就像上圖中的 programmer,你在為程式設計語言工作,如果你學會了使用 with 上下文管理器,那麼你就是一個 Python programmer,讓程式設計語言為你工作:

當程式退出 with 塊時,檔案會自動關閉。with 語句的文法格式:

相當于:

有很多網絡連接配接、資料庫連接配接庫都會提供 with 功能。甚至熟悉了 with 的實作機制後,可以自行實作 with 功能:

隻要定義了 <code>__enter__</code>,<code>__exit__</code>方法,就可以使用 with 語句:

疊代器:iterator 生成器:generator

疊代器和生成器都是 Python 中功能強大的工具,值得精通。疊代器是一個更籠統的概念:任何一個對象隻要它所屬的類具有<code>__next__</code>方法(Python 2是next)和具有傳回 self 的<code>__iter__</code>方法都是疊代器。

每個生成器都是一個疊代器,但反之不然。生成器是通過調用具有一個或多個 yield 表達式的函數而建構的,并且該函數是滿足上一段對iterator 的定義的對象。

使用差別:

網絡上很多技術部落客都說生成器是懶人版的疊代器,比疊代器更節省記憶體,其實是錯誤的,他們都很節省記憶體(我會舉例子)。

他們真正的差別是:當你需要一個具有某些複雜的狀态維護行為的類,或者想要公開除<code>__next__</code>(和<code>__iter__</code>和<code>__init__</code>)之外的其他方法時,你就需要自定義疊代器,而不是生成器。

通常,一個生成器(有時,對于足夠簡單的需求,一個生成器表達式)就足夠了,并且它更容易編寫代碼。

比如說計算正整數 a 到 b (b 遠遠大于 a)直接的平方,生成器的話就是:

或者:

如果是疊代器,則是這樣:

可以看出,疊代器寫起來稍麻煩,當也更為靈活,比如你想提供一個 current 方法時,可以直接添加到 Squares 類中:

從上述可以看出,疊代器并沒有儲存 a 到 b 之間的所有值,所有并不消耗過多的記憶體,這一點也可以自行測試,代碼如下:

可以看出 b 是 iterator,c 是 generator,它們占用的記憶體大小是一樣的。

itertools 子產品标準化了一個快速、高效利用記憶體的核心工具集,這些工具本身或組合都很有用。它們一起形成了“疊代器代數”,這使得在純 Python 中有可以建立簡潔又高效的專用工具。比如,如果你想要字元串中所有字元的組合或清單中數字的所有組合,則隻需編寫

這是一個值得經常使用的标準庫,更多詳細功能請參考官方文檔:https://docs.python.org/zh-cn/3/library/itertools.html[1]

這又是一個值得使用的标準庫 collections,它提供替代内置的資料類型的多個容器,如 defaultdict、OrderedDict、namedtuple、Counter、deque 等,非常使用,而且比自己實作要安全穩定的多。比如:

不多說了,看官方文檔:https://docs.python.org/3/library/collections.html[2]

不要過度使用類。堅持用 Java 和 C ++ 的程式員會經常使用類,但是在使用 Python 時,可以在函數和子產品的幫助下複用代碼。除非絕對需要,否則不必建立類。

本文講述類 8 個讓你寫出更好 Python 代碼的方法,希望對你有所幫助。

推薦閱讀:

10個技巧讓你的代碼更優雅

6 個值得玩味的 Python 代碼

[1]

https://docs.python.org/zh-cn/3/library/itertools.html: https://docs.python.org/zh-cn/3/library/itertools.html

[2]

https://docs.python.org/3/library/collections.html: https://docs.python.org/3/library/collections.html

繼續閱讀