作为动态性的强类型脚本语言,Python中的变量在定义的时候并不会指明具体类型,
Python解释器会在运行时自动进行类型检査并根据需要进行隐式类型转换。
按照Python的理念,
为了充分利用其动态性的特征是不推荐进行类型检查的。
如下面的函数 add()
,在 无需对参数进行任何约束的情况下便可以轻松地实现字符串的连接、数字的加法、列表的 合并等多种功能,
甚至处理复数都非常灵活。解释器能够根据变量类型的不同调用合适的内部方法进行处理,
而当a、b类型不同而两者之间又不能进行隐式类型转换时便抛出 TypeError
异常。
def add(a,b):
return a+b
print (add(1, 2j))
(1+2j)
print (add ('a' , 'b') )
ab
print (add (1,2))
3
print (add(1.0, 2.3))
3.3
print (add([1,2],[2, 3]))
[1, 2, 2, 3]
# print (add (1,' a')) #此代码会报错
if type(a) is types.ListType:
所有基本类型对应的名称都可以在 types
模块中找到,如 types.BooleanType
、 types.IntType
、
types.StringType
、 types.DictType
等。然而使用 type()
函数并不是就意味着可以高枕无忧了,
主张“不推荐使用 type
来进行变量类型检查”是有一定的缘由的。来看下面几个示例。
示例一:下例中用户类 UserInt
继承 int
类实现定制化,它不支持操作符 +=
。具体代码如下:
import types
class UserInt (int) :#i;at 为 CJserlnt 的基类
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):#①Userlnt 不支持操作
raise NotImplementedError ("not support operation")
def __str__(self):
return str(self._val)
def __repr__(self):
return 'Integer (%s) ' %self._val
n = UserInt()
print (n)
0
m = UserInt(2)
print (m)
2
print (n+m)
2
print (type(n) )
<class '__main__.UserInt'>
上例说明 type()
函数认为 n
并不是 int
类型,但 Userlnt
继承自 int
,显然这种判断不合理。
由此可见基于内建类型扩展的用户自定义类型,type
函数并不能准确返回结果。
示例二:在古典类中,所有类的实例的 type
值都相等。
class A:
pass
a = A()
class B:
pass
b =B()
type (a)==type(b)
False
在古典类中,任意类的实例的 type()
返回结果都是 <type 'instaiic'>
。
这种情况下使用 type()
函数来确定两个变最类型是否相同显然结果会与理解的大相径庭。
使用 isinstance
检测数据类型
因此对于内建的基本类型来说,也许使用 type()
进行类型检査问题不大,但在某些特殊场合 type()
方法并不可靠。
那么究竟应怎样来约束用户的输入类型从而使之与期望的类型一致呢?
答案是:如果类型有对应的工厂函数,可以使用工厂函数对类型做相应转换,
如 list(listing)
、 str(name)
等,
否则可以使用 isinstance()
函数来检测,其原型如下:
isinstance(object, classinfo);
其中,classinfo
可以为直接或间接类名、基本类型名称或者由它们组成的元组,
该函数在 classinfo
参数错误的情况下会抛出 TypeError
异常3 isinstance
基本用法举例如下:
isinstance (2,float )
False
isinstance ( (2, 3) , (str, list, tuple))#①支持多种类型列表 True
True
因此示例一中可以将 print typc(n) is types.lntType
改为 print isinstance(n,int)
,
以获取正确的结果。