Python code smells 實例講解

發(fā)布時間:2022-03-11 21:34:40  |  來源:騰訊網(wǎng)  

code smells可以理解為代碼中讓人感覺到不舒服的地方??赡苁谴a規(guī)范問題,也可能是設(shè)計上的缺陷。

很多時候一段代碼符合基本邏輯,能夠正常運行,并不代表它是不“丑”的。代碼中可能會存在諸如可讀性差、結(jié)構(gòu)混亂、重復(fù)代碼太多、不夠健壯等問題。

示例代碼

上述代碼實現(xiàn)了一個簡單的“員工管理系統(tǒng)”。

Employee 類代表公司里的員工,有姓名、角色、假期等屬性??梢哉埣伲ǎ?,或者單獨請一天,或者以 5 天為單位將假期兌換為報酬

HourlyEmployee 和 MonthlyEmployee 分別代表以時薪或者月薪來計算工資的員工

Company 類代表公司,可以招收員工()、返回特定角色的員工列表(如 )、發(fā)放薪資等()

code smells

上面的代碼中存在著很多可以改進的地方。

用 Enum 類型替代 str 作為員工的 role 屬性

上面的 類使用了 類型來存儲 屬性的值,比如用 代表經(jīng)理,用 代表實習(xí)生。

實際上 String 過于靈活,可以擁有任何含義,用來表示角色屬性時不具有足夠清晰的指向性。不同的拼寫規(guī)則和大小寫習(xí)慣都會導(dǎo)致出現(xiàn)錯誤的指向,比如 和 , 和 ??梢允褂?Enum 替代 str。

修改 類中 屬性的定義:

類中 等方法也做相應(yīng)的修改:

方法中使用新的 role 創(chuàng)建員工對象:

消除重復(fù)代碼

類中有一個功能是返回特定角色的員工列表,即 、、 三個方法。

這三個方法實際上有著同樣的邏輯,卻分散在了三個不同的函數(shù)里??梢院喜⒊梢粋€方法來消除重復(fù)代碼。

同時將 函數(shù)中的 、、 都改為如下形式:

盡量使用內(nèi)置函數(shù)

上面版本中的 方法,包含了一個 循環(huán)。實際上該部分邏輯可以使用 Python 內(nèi)置的列表推導(dǎo)來實現(xiàn)。

合理的使用 Python 內(nèi)置函數(shù)可以使代碼更短、更直觀,同時內(nèi)置函數(shù)針對很多場景在性能上也做了一定的優(yōu)化。

更清晰明確的變量名

舊版本:

新版本:

isinstance

當(dāng)你在代碼的任何地方看到 這個函數(shù)時,都需要特別地加以關(guān)注。它意味著代碼中有可能存在某些有待提升的設(shè)計。

比如代碼中的 函數(shù):

這里 的使用,實際上在 函數(shù)中引入了對 的子類的依賴。這種依賴導(dǎo)致各部分代碼之間的職責(zé)劃分不夠清晰,耦合性變強。

方法需要與 的子類的具體實現(xiàn)保持同步。每新增一個新的員工類型( 的子類),此方法中的 也就必須再新增一個分支。即需要同時改動不同位置的兩部分代碼。

可以將 的實現(xiàn)從 類轉(zhuǎn)移到具體的 子類中。即特定類型的員工擁有對應(yīng)的報酬支付方法,公司在發(fā)薪時只需要調(diào)用對應(yīng)員工的 方法,無需實現(xiàn)自己的 方法。由 引入的依賴關(guān)系從而被移除。

再把 函數(shù)中的 改為 。

由于每一個特定的 子類都需要實現(xiàn) 方法,更好的方式是將 實現(xiàn)為虛擬基類, 成為子類必須實現(xiàn)的虛擬方法。

Bool flag

類中的 方法有一個名為 的參數(shù)。它是布爾類型,作為一個開關(guān),來決定某個員工是請一天假,還是以 5 天為單位將假期兌換為報酬。

這個開關(guān)實際上導(dǎo)致了 方法包含了兩種不同的職責(zé),只通過一個布爾值來決定具體執(zhí)行哪一個。

函數(shù)原本的目的就是職責(zé)的分離。使得同一個代碼塊中不會包含過多不同類型的任務(wù)。

因此 方法最好分割成兩個不同的方法,分別應(yīng)對不同的休假方式。

Exceptions

方法中有一步 代碼。但該部分代碼實際上對 Exception 沒有做任何事。對于 Exception 而言:

如果需要 catch Exception,就 catch 特定類型的某個 Exception,并對其進行處理;如果不會對該 Exception 做任何處理,就不要 catch 它。

在此處使用 會阻止異常向外拋出,導(dǎo)致外部代碼在調(diào)用 時獲取不到異常信息。此外,使用 而不是某個特定類型的異常,會導(dǎo)致所有的異常信息都被屏蔽掉,包括語法錯誤、鍵盤中斷等。

因此,去掉上述代碼中的 。

使用自定義 Exception 替代 ValueError

是 Python 內(nèi)置的在內(nèi)部出現(xiàn)值錯誤時拋出的異常,并不適合用在自定義的場景中。最好在代碼中定義自己的異常類型。

最終版本

參考資料

7 Python Code Smells: Olfactory Offenses To Avoid At All Costs

來源:

https://www.starky.ltd/2021/12/06/7-python-code-smells-by-practical-example/

關(guān)鍵詞: Python code smells 實例講解 exception python

 

網(wǎng)站介紹  |  版權(quán)說明  |  聯(lián)系我們  |  網(wǎng)站地圖 

星際派備案號:京ICP備2022016840號-16 營業(yè)執(zhí)照公示信息版權(quán)所有 郵箱聯(lián)系:920 891 263@qq.com