天天看點

五大代碼異味:你需要提高警惕了![5][5, 5]

五大代碼異味:你需要提高警惕了![5][5, 5]

作為廣泛應用的警告标志,與字面意思不同,代碼異味并不是指代碼中需要立即注意的漏洞。相反,它反映出代碼中更深層次的問題,更确切地說是代碼中的裂縫,如果不加以糾正,這些問題可能會在未來導緻更嚴重的後果。

代碼異味是弱點或設計缺陷的标志,可能會在可讀性、可維護性和可拓展性上導緻問題,通常是由不當做法和未使用正确的工具導緻的。

Python是最流行的語言之一,這在很大程度上與其相當容易的學習曲線和高度僞英語句法有關,而這卻容易令人陷入單一的做事方法。本文中,我們将了解一些典型的Python代碼異味案例以及如何避免它們。

可變預設參數

在Python中,使用預設參數是一個很常見的操作,你可以設定一個預定值,并在調用時選擇更改。這在設定文字、數字或布爾值時很有用,因為有助于避免出現較長的有備援值的參數清單。

但是将可變的值設定為預設參數可能是危險的,并且會導緻bug。來看以下示例:

def addElements(a=[]):           
a.append(5)
return aaddElements()                

[5]

addElements()

[5, 5]

相同的函數在每次調用時給出不同的結果。Python中可變預設值的問題是它們隻在定義函數時計算一次。每次調用函數時,使用變異值,可能會導緻意外的問題,因為跟蹤函數調用真的很麻煩。

是以,使用None作為預設值,并在函數中配置設定可變變量是更安全的,因為你不會以可維護性問題結束,隻有在确定需要時才使用可變的預設參數。

選擇

range

而不是

enumerate

Python的for循環不是最常用的代碼編寫方式,但有時也會需要到。現在,Python中的for 循環的運作與其他語言不同,你可能會本能地以非慣用的方式編寫傳統風格的range(len()),如下所示:

names =["a", "b", "c"]for i in range(len(names)):           
print(i, names[i])                

重複基于C-style索引的循環是相當常見的,但這是一種不當做法。其迫使你通過顯式索引變量通路元素,是以它不僅Python特性不明顯,而且還存在可讀性問題。

使用enumerator能提供一個元組的優勢,該元組負責同時跟蹤索引值和元素。除了更簡便,優化程度還更高,它還提供了可選的第二個參數來設定數值。

for i, name in enumerate(names):
   print(i, name)
           

忽略内置函數和過度循環

循環不是不能用,但在其中應用轉換操作時,它可能會導緻冗長的條件代碼。在這種情況下,不要忽略已經可以使用的内置函數,如map()filter()和reduce(),這是非常重要的。更重要的是,Python提供了清單解析,這顯然是最具Python特性的替換循環方法。

嵌套for循環是代碼異味的另一個典型例子。Python程式員在進行模式比對或一起運作多個疊代時很容易中槍。下列代碼一旦再加幾行就會看起來不美觀:

for x in listA:           
for y in listB:
    r.append((x, y))                

使用itertools不僅可以提高性能,還更簡潔明了。看看上面的代碼在itertools.product()中有多整潔:

for x, y in itertools.product(listA,listB):           
r.append((x, y))                

通過使用上面的product,也可以很容易地将其傳遞到其他高階函數中。同時在多個清單上同時疊代時,使用zip()函數也不錯(如需索引,還可以使用enumerator)。

濫用清單解析

清單解析能靈活建立清單,功能強大,但很容易被誤用或濫用,來看一些案例。

  • 在不需要時過度進行清單解析

通常,我們開始沉迷于使用清單解析是為了嘗試花哨的東西,而不是真需要它。比如在簡單的情況下可以使用清單構造函數:

names ="A","B","C"#use this
list(map(str.lower, names))
           
  • 在實際不存儲時使用清單解析

清單解析有助于輕松定義和建立清單,但它們始終存儲于記憶體中。如果不使用系統程序,将有可能損害大數量的資料。是以,使用生成器表達式是更好的選擇,因為它按需一次加載一個值。

嵌套分析也需要關注,因為這可能導緻可讀性問題,知道什麼時候使用它,什麼時候回退到for循環上是很重要的。

喜歡布爾标志參數和全局變量

布爾是最容易學習的資料類型。在Python中,提供命名參數使工作輕松得多。但是,它們很容易産生嵌套if else塊的複雜代碼并導緻可讀性問題。多個布爾存在隐藏的依賴關系,會産生一些問題。因而最好使用枚舉,而不是多布爾邏輯。Enum資料類型是可擴充的,可以確定更好的代碼結構。

全局變量在所有語言中都是麻煩的,Python也是如此。雖然有時我們确實需要使用它們,但将其誤用作傳遞或通路資料的快捷方式可能很危險,因為它可變。

跟蹤它的狀态會很棘手,因為你永遠不知道誰可能會改變它。如果開始到處使用全局變量,命名沖突則會導緻命名空間受到不好的影響。

五大代碼異味:你需要提高警惕了![5][5, 5]

我們都見過代碼異味,神秘的注釋、多餘的字元串文字和神奇的數字也算代碼異味。在編寫注釋時,重要的是要說明“為什麼”部分,因為“什麼”部分應該從代碼本身得到解釋。

你得學會快速定位到代碼異味并将其去除。

原文釋出時間:2020-08-02

本文作者:讀芯術