Python中的型別檢查

weixin_33918357發表於2017-03-25

本文中所有程式碼均執行在Python 2.7上

為什麼要進行型別檢查?

總所周知,Python是一門典型的動態語言,在變數定義、使用的過程中遵循duck typing,當對某一變數進行操作時才去檢查它是否支援該操作。這在大多數情況下沒有什麼問題。但有時我們希望當面對非法型別的引數的時候採取某些預設處理機制,來提高程式的健壯性,而不是直接丟擲異常停掉整個程式。
舉個例子:

def list_add(list1, list2):
    for item in list2:
        list1.append(item)
    return list1

上面是一個很簡單的方法,將第二個列表中的元素依此追加在第一個列表之後。這要求list1變數型別支援append方法,list2變數本身是可迭代的。如果我們傳入兩個int型別的變數來呼叫這個方法,就會丟擲TypeError的異常。

type

在進行型別檢查的時候,大多數人至少都會知道使用type方法,這是比較常見的方法。
再來幾個例子:

>>> import typea
>>> type(1) is types.IntType
True
>>> type(True) is types.booleanType
True
>>> type(1.22) is types.StringType
False

看起來不錯,似乎可以應付絕大多數情況,但有的時候還是會有點問題:

import types
# 我們建立了一個繼承自int的類,不進行任何重寫,按照duck typing的原則,它應該被按照int進行處理
>>> class A(int):
...       pass
>>> b = A()
>>> type(b) is types.IntType
False

可見,基於Python內建(bult-in)型別的自定義型別,python並不能返回我們期望的結果。
不僅如此,type對於古典類(古典類和新式類的區別)的型別判斷似乎也有點問題:

>>> class A:
...        pass
>>> class B:
...        pass
>>> a = A()
>>> b = B()
>>> type(a) == type(b)
True
>>> type(a)
<type 'instance'>
>>> type(b)
<type 'instance'>

可見,對於所有古典類,type返回的結果是一樣的。
綜上所述,對於常見的內建型別,type可以返回我們期望的結果,但在某些情形下,似乎會有點問題。

isinstance

isinstance可以解決上面所提到的type可能存在的問題。
首先看一下常見情況下:

>>> isinstance(1, int)
True
>>> isinstance('Hello', basestring)
True
>>> isinstance(1.23, float)
True
>>> isinstance([1,2], dict)
False

接下來看看對於繼承自內建型別的自定義型別的判斷:

>>> class A(int):
...       pass
>>> a = A()
>>> isinstance(a, int)
True

之後來看看古典類的情況:

>>> class A:
...        pass
>>> class B:
...        pass
>>> a = A()
>>> b = B()
>>> isinstance(a, A)
True
>>> isinstance(a, B)
False
>>> isinstance(b, B)
True
>>> isinstance(b, A)
False

得到了我們所期望的效果。

總結

鑑於在某些情況下,type()可能會出現的問題,為確保程式的正常執行,一般情況下推薦使用isinstance()來進行型別判斷。

相關文章