本文中所有代码均运行在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(b)
可见,对于所有古典类,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()来进行类型判断。