Python中,type和isinstance都可以进行类型检查,用的最多的就是type()了(其实我是一直用type())。内建函数type(object)用于返回当前对象的类型,比如type(1)返回<type 'int'>。因此可以通过与python自带模块types中所定义的名称进行比较,根据其返回值确定变量类型是否符合要求。例如判读一个变量a是不是list类型,可以使用以下代码:
if type(a) is types.ListType:
所有的基本类型对应的名称都可以在types模块中找得到,如types.BooleanType、types.IntType等等,在安装目录下lib文件夹里,名为types.py。实现方法很简单,把对应的类型赋值给变量。源代码如下:
import sys# Iterators in Python aren't a matter of type but of protocol. A large# and changing number of builtin types implement *some* flavor of# iterator. Don't check the type! Use hasattr to check for both# "__iter__" and "next" attributes instead.NoneType = type(None)TypeType = typeObjectType = objectIntType = intLongType = longFloatType = floatBooleanType = booltry: ComplexType = complexexcept NameError: passStringType = str# StringTypes is already outdated. Instead of writing "type(x) in# types.StringTypes", you should use "isinstance(x, basestring)". But# we keep around for compatibility with Python 2.2.try: UnicodeType = unicode StringTypes = (StringType, UnicodeType)except NameError: StringTypes = (StringType,)BufferType = bufferTupleType = tupleListType = listDictType = DictionaryType = dictdef _f(): passFunctionType = type(_f)LambdaType = type(lambda: None) # Same as FunctionTypeCodeType = type(_f.func_code)def _g(): yield 1GeneratorType = type(_g())class _C: def _m(self): passClassType = type(_C)UnboundMethodType = type(_C._m) # Same as MethodType_x = _C()InstanceType = type(_x)MethodType = type(_x._m)BuiltinFunctionType = type(len)BuiltinMethodType = type([].append) # Same as BuiltinFunctionTypeModuleType = type(sys)FileType = fileXRangeType = xrangetry: raise TypeErrorexcept TypeError: tb = sys.exc_info()[2] TracebackType = type(tb) FrameType = type(tb.tb_frame) del tbSliceType = sliceEllipsisType = type(Ellipsis)DictProxyType = type(TypeType.__dict__)NotImplementedType = type(NotImplemented)# For Jython, the following two types are identicalGetSetDescriptorType = type(FunctionType.func_code)MemberDescriptorType = type(FunctionType.func_globals)del sys, _f, _g, _C, _x # Not for export__all__ = list(n for n in globals() if n[:1] != '_')
然而,使用type()函数并不是意味着可以高枕无忧了,看看下面的例子就明白了。下面的例子用户类UserInt继承int类型实现定制化,它不支持操作符+=,代码如下:
#coding=utf-8import typesclass UserInt(int): def __init__(self,val=0): self._val = int(val) def __add__(self, val): if isinstance(val,UserInt): return UserInt(self._val + val._val) return self._val + val def __iadd__(self, val): raise NotImplementedError("not support opeation") def __str__(self): return str(self._val) def __repr__(self): return "Integer(%s)"%self._valn = UserInt()print nm=UserInt(2)print mprint n + mprint type(n) is types.IntType
输出结果如下:
0
2
2
False
上例中type()语句输出的是False,这说明type()函数认为n并不是int类型,但UserInt确确实实是继承自int,显然这种判读是不合理的。由此可见基于内建类型扩展的用户自定义类型,type函数并不能准确的返回结果。
再看下面一个例子
class A: passa = A()class B: passb = B()print type(a) == type(b)
输出结果是True,并不是False,上面两个类是古典类,在古典类中,任意类的实例的type()返回结果都是<type 'instance'>。这种情况下使用type()函数确定两个变量类型是否相同,那么得到的结果会截然相反的。
对于内建基本类型来说,用type()进行类检查可能没有问题,但是在某些特定情况就不行了。那么究竟怎样约束用户的输入类型从而使之与我们期望的类型一致呢?如果类型有对应的工厂函数,可以使用工厂函数对类型做相应转换,如list(),str(),否则可以使用isinstance()函数来检查。原型如下
isinstance(object, classinfo)
其中,classinfo可以为直接或间接类名、基本类型名称或者由它们组成的元组,该函数在classinfo参数错误的情况下会抛出TypeError异常
>>>isinstance(2,float)False>>>isinstance("a",(str,unicode))True>>>isinstance((2,3),(str,list,tuple))True
因此上面的print type(n) is types.IntType改为print isinstance(n,int),就可以获得正确结果。