>>> from env_helper import info; info()
页面更新时间: 2023-08-25 16:07:51
运行环境:
    Linux发行版本: Debian GNU/Linux 12 (bookworm)
    操作系统内核: Linux-6.1.0-11-amd64-x86_64-with-glibc2.36
    Python版本: 3.11.2

2.5. 不推荐使用 type 来进行类型检查

作为动态性的强类型脚本语言,Python中的变量在定义的时候并不会指明具体类型, Python解释器会在运行时自动进行类型检査并根据需要进行隐式类型转换。 按照Python的理念, 为了充分利用其动态性的特征是不推荐进行类型检查的。 如下面的函数 add() ,在 无需对参数进行任何约束的情况下便可以轻松地实现字符串的连接、数字的加法、列表的 合并等多种功能. 甚至处理复数都非常灵活。解释器能够根据变量类型的不同调用合适 的内部方法进行处理. 而当a、b类型不同而两者之间又不能进行隐式类型转换时便抛出 TypeError 异常。

>>> def add(a,b):
>>>     return a+b
>>> print (add(1, 2j))
>>> print (add ('a'  , 'b') )
>>> print (add (1,2))
>>> print (add(1.0, 2.3))
>>> print (add([1,2],[2, 3]))
>>> print (add (1,' a'))
(1+2j)
ab
3
3.3
[1, 2, 2, 3]
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-2-a4d32a0665d0> in <module>()
      6 print (add(1.0, 2.3))
      7 print (add([1,2],[2, 3]))
----> 8 print (add (1,' a'))


<ipython-input-2-a4d32a0665d0> in add(a, b)
      1 def add(a,b):
----> 2     return a+b
      3 print (add(1, 2j))
      4 print (add ('a'  , 'b') )
      5 print (add (1,2))


TypeError: unsupported operand type(s) for +: 'int' and 'str'

不刻意进行类型检查,而是在出错的情况下通过抛出异常来进行处理.这是较为常见的方式。 但实际应用中为了提高程序的健壮性, 仍然会面临需要进行类型检査的情景。 那么使用什么方法呢?很容易想到,使用 type()

内建函数 type(object) 用于返回当前对象的类型,如 type(1) 返回 <type'int'> 。 因此可以 通过与Python自带模块type中所定义的名称进行比较,根据其返回值确定变量类型是否符合要求。 例如判断一个变量 a 是不是 list类型可以使用以下代码:

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)
>>> m = UserInt(2)
>>> print (m)
>>> print (n+m)
>>> print (type(n) )
0
2
2
<class '__main__.UserInt'>

上例标注②处输出False,这说明 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() 函数来确定两个变最类型是否相同显然结果会与我们所理解的大相径庭。

2.5.1. 使用 isinstance 检测数据类型

因此对于内建的基本类型来说,也许使用 type() 进行类型检査问题不大,但在某些特殊场合 type() 方法并不可靠。 那么究竟应怎样来约束用户的输入类型从而使之与我们期望的类型一致呢? 答案是:如果类型有对应的工厂函数,可以使用工厂函数对类型做相应转换, 如 list(listing)str(name) 等, 否则可以使用 isinstance() 函数来检测,其原型如下:

isinstance(object, classinfo);

其中,classinfo可以为直接或间接类名、基本类型名称或者由它们组成的元组, 该函数 在classinfo参数错误的情况下会抛出TypeError异常3 isinstance基本用法举例如下:

>>> isinstance (2,float )
False

isinstance("a",(str,unicode))

>>> isinstance ( (2, 3) , (str, list, tuple))#①支持多种类型列表 True
True

因此示例一中可以将 print typc(n) is types.lntType 改为 print isinstance(n,int),以获取正确的结果。