碼??!12 種生產(chǎn)級 Python 代碼風(fēng)格
在工作中,我們編寫的代碼盡可能地易于理解,這意味著:
- 變量名有意義且更長(而不是 a、b 和 c)
- 函數(shù)名稱有意義且更長
- 大量注釋和文檔來解釋代碼
- 類型提示無處不在
- 字符串似乎更長、更冗長
- 等等等等
因此我們需要不斷精進(jìn)自己的編碼能力,以適應(yīng)更多的要求。
下面就跟大家分享一下以下堪稱一絕的生產(chǎn)級 Python 代碼風(fēng)格。
1 使用括號解包元組
以下是一些常規(guī)元組的解包:
圖片
在生產(chǎn)級代碼中,我們通常不使用諸如 a 或 b
因此,我們可以使用括號來幫助元組解包,如下所示:
圖片
請注意,通過這種方式,我們的元組解包可以容納更長(且更具描述性)的變量名。
一個(gè)工作中的例子:
圖片
2 多行列表推導(dǎo)式
正常的列表推導(dǎo)式如下所示:
圖片
在生產(chǎn)代碼中,我們通常不使用變量名 i
我將如何重寫上述代碼:
圖片
一個(gè)工作中的例子:
圖片
3 使用括號組合字符串
生產(chǎn)級字符串通常太冗長,無法放在一行中。因此我們使用括號將它們組合起來。
圖片
注意:在括號內(nèi),字符串文字(使用引號)會(huì)自動(dòng)相加,我們不需要使用 + 運(yùn)算符來執(zhí)行此操作
4 使用括號進(jìn)行多行方法鏈接
正常方法鏈接:
圖片
在生產(chǎn)級代碼中,方法名稱大多數(shù)時(shí)候都更長,并且我們將更多方法鏈接在一起。
我們使用括號將所有這些內(nèi)容分成多行,而不是縮短任何方法名稱或變量名稱。
圖片
請注意,如果我們在括號內(nèi)進(jìn)行方法鏈接,則不需要使用 \ 字符進(jìn)行顯式換行
5 索引嵌套字典
索引嵌套字典的正常方式:
圖片
這里存在一些問題:
- 生產(chǎn)級代碼中的字典有更多嵌套層級
- 字典鍵的名稱更長
- 我們通常無法將整個(gè)嵌套索引代碼壓縮到一行中。
因此,我們將其分成多行,如下所示:
圖片
如果這還不夠的話,我們將索引代碼分成更多行:
圖片
或者如果我們?nèi)匀话l(fā)現(xiàn)這很難閱讀,我們可以這樣做:
圖片
6 編寫可讀且信息豐富的函數(shù)
通常,新手是這樣編寫函數(shù)的:
圖片
包含此類代碼的 PR 很可能會(huì)被拒絕
- 函數(shù)名稱不具描述性
- 參數(shù)變量名不好
- 沒有類型提示,所以我們乍一看不知道每個(gè)參數(shù)應(yīng)該是什么數(shù)據(jù)類型
- 沒有類型提示,所以我們也不知道函數(shù)應(yīng)該返回什么
- 沒有文檔字符串,所以我們必須推斷函數(shù)的作用
以下是我們在生產(chǎn)級 Python 代碼中編寫函數(shù)的方法
圖片
- 函數(shù)名稱應(yīng)該具有描述性
- 參數(shù)名稱應(yīng)該更具描述性,而不是例如 a、b、c
- 每個(gè)參數(shù)都應(yīng)該有一個(gè)類型提示
- 函數(shù)的返回類型也應(yīng)該包括在內(nèi)
- 詳細(xì)說明函數(shù)功能、函數(shù)所接受的參數(shù)及其輸出的文檔字符串應(yīng)以三重引號中的字符串形式包含在內(nèi)。
7 盡可能減少縮進(jìn)級別
這是一個(gè) for 循環(huán)。如果條件滿足,我們就執(zhí)行某些操作。
圖片
一些同事和高級工程師可能實(shí)際上會(huì)對這段代碼有所不滿——通過減少縮進(jìn)級別可以寫得更好。
我們重寫這個(gè)代碼,同時(shí)減少do_something()的縮進(jìn)級別。
圖片
請注意, do_something()的縮進(jìn)級別已減少了 1 級,只需使用 if not condition而不是if condition。
在生產(chǎn)級代碼中,縮進(jìn)級別可能會(huì)更多,如果縮進(jìn)太多,我們的代碼就會(huì)變得煩人且難以閱讀。因此,這個(gè)技巧可以讓我們的代碼更整潔、更易于閱讀,
8 帶括號的布爾條件
這是一個(gè)使用and關(guān)鍵字連接起來的包含 3 個(gè)條件的 if 語句。
圖片
在生產(chǎn)級代碼中,條件會(huì)變得更長,并且可能會(huì)有更多條件。因此,我們可以解決這個(gè)問題的一種方法是將這個(gè)巨大的條件重構(gòu)為一個(gè)函數(shù)。
或者,如果我們認(rèn)為沒有必要為此編寫新函數(shù),則可以使用括號編寫條件語句。
圖片
這樣,我們就不會(huì)被迫為這一個(gè)條件語句編寫一個(gè)新的函數(shù)或變量,同時(shí)我們還能保持它的整潔和可讀性。
有時(shí)我可能實(shí)際上更喜歡這樣寫,盡管這只是基于個(gè)人喜好:
圖片
9 防止 None 值
訪問對象某些嵌套屬性的普通代碼。
圖片
此代碼中的一些問題可能會(huì)導(dǎo)致我們的 PR 被拒絕:
- 如果dog為 None,我們會(huì)收到錯(cuò)誤
- 如果dog.owner為 None,我們也會(huì)收到錯(cuò)誤
- 本質(zhì)上,這段代碼不能防止dog或dog.owner為 None 的可能性。
在生產(chǎn)級代碼中,我們需要積極防范此類情況。下面是我重寫此代碼的方法。
圖片
Python 中的 and 和 or
- 如果 dog 為 None,我們的表達(dá)式終止于 “if dog
- 如果 dog 不為 None,但 dog.owner 為 None,則表達(dá)式終止于“ if dog and dog.owner
- 如果我們沒有任何 None 值,則可以成功訪問dog.owner.name,并將其與字符串“bob”進(jìn)行比較
這樣,我們就有了額外的保護(hù),防止dog或dog.owner為 None 值的可能性。
10 防止迭代 None 值
以下是我們?nèi)绾蔚承┛傻鷮ο螅ɡ缌斜怼⒆值?、元組等)
圖片
這樣做的一個(gè)問題是,它不能防止 mylist 為 None —— 如果 mylist
以下是我對這段代碼的改進(jìn):
圖片
表達(dá)式 “mylist or None”
- 如果 mylist
- 如果 mylist
因此,如果 mylist 為 None,則表達(dá)式 “mylist or None”
11 內(nèi)部函數(shù)以 _ 開頭
這是一個(gè)示例類。在這里,run方法使用其他方法 clean 和 transform
圖片
在生產(chǎn)級代碼中,我們希望盡可能明確,因此嘗試區(qū)分內(nèi)部和外部方法。
- 外部方法——供其他類和對象使用的方法
- 內(nèi)部方法——類本身使用的方法
按照慣例,內(nèi)部方法以下劃線 _ 開頭是一種很好的做法
如果我們重寫上面的代碼,我們會(huì)得到:
圖片
注意:在方法名前面添加下劃線并不會(huì)將其隱藏在其他類和對象中。事實(shí)上,功能上沒有區(qū)別。
12 常用功能裝飾器
這是一個(gè)包含 3 個(gè)函數(shù)的類,每個(gè)函數(shù)執(zhí)行不同的操作。但是,請注意,不同函數(shù)之間的步驟類似 — try-except 塊以及日志記錄功能。
圖片
減少重復(fù)代碼量的一個(gè)很好的做法是編寫一個(gè)包含常用功能的裝飾函數(shù)。
圖片
這樣,如果我們想要更新公共代碼(try-except 和日志代碼),我們不再需要在 3 個(gè)地方更新它們 - 我們只需要更新包含公共功能的裝飾器代碼。