Python 初學者常犯的5個錯誤,布林型竟是整型的子類

視學演算法發表於2020-04-06

作者:Mohit

機器之心編譯

參與:

Python 是一種神奇的語言,看似簡單便捷,但總會有一些意想不到的驚喜在等著我們。比如說,assert 在正式環境下根本不會執行,isinstance(False, int) 竟然輸出 True。

Python 是一種高階的動態程式語言,它以易於使用著名。目前 Python 社群已經非常完善了,近幾年它的發展尤為迅猛。但是易於使用同樣能帶來一些壞處,即易於誤用。在本文中,作者列舉了 5 個初學者常犯的錯誤,希望它們能幫助初學者寫更加正確與優美的程式碼。

1. 可變的預設引數

Python 中的預設引數會在執行函式定義時計算一次,這表示在函式完成定義後該表示式只執行一次,因此預設值可以用於後續的每一次呼叫。如果我們令預設引數為可變的,例如列表或字典等,那麼對於將來所有的呼叫,該引數都是一直保留且可變的。

如下為不正確的表達方式,如果我們第一次呼叫 add_item 增加「a」時,items=[『a』]。當我們第二次呼叫 add_item 增加「b」時,由於定義中的 items=[] 只在初始化的時候執行一次,因此這時的 items=[『a』, 『b』]。

尤其是當我們在呼叫 add_item 函式時沒傳入任何引數,那麼 items 還是能保留以前記住的內容,相當於將以前的內容洩漏給了後續的呼叫。

def add_item(new_item, items=[]):
    items.append(new_item)

正確的表達方式應該是如下,在我們沒傳入 items 時應該要將它初始化為空白列表:

def add_item(new_item, items=None):
    if items is None:
        items = []
    items.append(new_item)

2. 將 assert 宣告語句作為保證條件

因為 assert 語句很容易檢查一些條件是否滿足或執行是否正確,開發者經常用它來檢查某部分程式碼的有效性。但是當 Python 直譯器呼叫時帶了-O (optimize) flag,那麼 assert 語句會從位元組碼中移除。所以,如果 assert 語句在面向使用者驗證的產品程式碼中,根本就不會執行,因為它可能會造成一些安全漏洞。

因此開發者應該只在測試中使用 assert 語句,不正確的示例如下:

assert re.match(VALID_ADDRESS_REGEXP, email) is not None

正確的程式碼要改成:

if not re.match(VALID_ADDRESS_REGEXP, email):
    raise AssertionError

3. 使用 isinstance 代替 type

type 和 isinstance 都能檢查某個物件的類別是什麼。但是它們間有非常重要的區別,isinstance 在解析目標型別時,它會關注繼承關係,而 type 並不會。正因為這個區別,isinstance 在某些時候並不是我們所想的那樣。例如以下案例:

def which_number_type(num):
    if isinstance(num, int):
        print('Integer')
    else:
        raise TypeError('Not an integer')

which_number(False)  # prints 'Integer', which is incorrect

因為布林型別的變數在 Python 中是 int 的子類,isinstance(num, int) 同樣會得出 True,這並不是我們想要的。在特定的類別中,使用 type 可能更加正確。

4. 不必要的 lambda 表示式

函式在 Python 中是最常用的結構,我們能將函式賦值給某個變數,並將該變數作為引數傳遞給另外一個函式,這也是函式常見的用法。但這對於初學者或瞭解其它程式語言的開發者而言,這種傳遞方式是非常反直覺的。

一個比較常見的模式可以表示為:

def request(self, method, **kwargs):
    # ...
    if method not in ("get""post"):
        req.get_method = lambda: method.upper()
    # ...

上面採用匿名函式 lambda 的方式,最好可以改成以下:

def request(self, method, **kwargs):
    # ...
    if method not in ("get""post"):
        req.get_method = method.upper
    # ...

5. NotImplemented錯誤。這種命名可能會使開發者感到困惑,NotImplementedError 是一種 exception 類,當派生類需要重寫某個方法時,Python 應該觸發這類錯誤。而 NotImplemented 是一個常量,它用於實現二進位制操作。當我們觸發 NotImplemented 時,Python 會給出「TypeError」的報錯。

錯誤的例子:

class SitesManager(object):
    def get_image_tracking_code(self):
        raise NotImplemented

正確表達方法應該是:

class SitesManager(object):
    def get_image_tracking_code(self):
        raise NotImplementedError

原文連結:https://deepsource.io/blog/python-common-mistakes/

- END -

如果看到這裡,說明你喜歡這篇文章,請轉發、點贊掃描下方二維碼或者微信搜尋「perfect_iscas」,新增好友後即可獲得10套程式設計師全棧課程+1000套PPT和簡歷模板向我私聊「進群」二字即可進入高質量交流群。

掃描二維碼進群↓

Python 初學者常犯的5個錯誤,布林型竟是整型的子類

Python 初學者常犯的5個錯誤,布林型竟是整型的子類

Python 初學者常犯的5個錯誤,布林型竟是整型的子類

在看 Python 初學者常犯的5個錯誤,布林型竟是整型的子類

相關文章