isinstance(foo,bar)vs type(foo)是bar

Ada*_*ith 25 python typechecking

真的是一个语义问题.

直到最近,如果我不得不对结构进行任何类型检查,我会使用type(obj) is listet.人.然而,自从加入SO后,我注意到每个人(我的意思是每个人)都使用了isinstance(obj,list).它们似乎是同义词,并且timeit在它们之间显示出几乎相同的速度.

def a(): return type(list()) is list
def b(): return isinstance(list(),list)

from timeit import timeit
timeit(a)
# 0.5239454597495582
timeit(b)
# 0.5021292075273176
Run Code Online (Sandbox Code Playgroud)

事实上甚至dis同意他们是同义词,除了type is'sCOMPARE_OP

from dis import dis

dis(a)
# 2           0 LOAD_GLOBAL              0 (type) 
#             3 LOAD_GLOBAL              1 (list) 
#             6 CALL_FUNCTION            0 (0 positional, 0 keyword pair) 
#             9 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
#            12 LOAD_GLOBAL              1 (list) 
#            15 COMPARE_OP               8 (is) 
#            18 RETURN_VALUE

dis(b)
# 2           0 LOAD_GLOBAL              0 (isinstance)
#             3 LOAD_GLOBAL              1 (list) 
#             6 CALL_FUNCTION            0 (0 positional, 0 keyword pair) 
#             9 LOAD_GLOBAL              1 (list) 
#            12 CALL_FUNCTION            2 (2 positional, 0 keyword pair) 
#            15 RETURN_VALUE 
Run Code Online (Sandbox Code Playgroud)

我坦率地发现它if type(foo) is list:比说起来更可读if isinstance(foo,list):,第一个基本上只是伪代码而第二个调用一些函数(我必须每次都查找isinstance或者查询instanceof)和一些参数.它看起来不像是类型转换,并且没有明确的方法可以知道是否isinstance(a,b)正在检查是否b是实例,a反之亦然.

我从这个问题中理解我们使用isinstance它,因为它对继承更好.type(ClassDerivedFromList) is list会失败,但isinstance(ClassDerivedFromList,list)会成功.但是,如果我正在检查什么应该始终是一个基础对象,我真的会失去什么type is呢?

zmo*_*zmo 17

如果我正在检查什么应该始终是一个基础对象,那么我在做类型时真正失去了什么?

好吧,你很好地在你的问题中给出完整记录的答案,所以你的答案是你什么都没有失去!isinstance()必要的唯一时间是检查给定类的继承与另一个类的继承,正如您所说和引用的那样.type()应仅用于检查实例是否完全是给定的基本类型.

  • @adsmith:你使用Python 3吗?如果没有,如果你结束了unicode字符串,你的代码就会崩溃. (3认同)
  • 或者你可以简单地做`如果type(foo)是list:_handle_list(foo)else:_handle_str(foo)`.@DSM是完全正确的,要正确处理字符串,你需要检查`isinstance(foo,basestring)`.如果我是你,我实际上会检查`if type(foo)是否为list:_handle_list(foo)elif isinstance(foo,basestring):_ handlele_str(foo)else raise Exception("Type Not Handled")`. (3认同)

use*_*028 5

除了继承问题,您还失去了在使用时测试多种类型的能力isinstance.例如:

def chk(typ):
    if not isinstance(typ, (str, int)):
        raise ValueError('typ must be string or int')
    ...
Run Code Online (Sandbox Code Playgroud)

  • 你总是可以在(str,int)`中输入`type(x). (14认同)

arc*_*don 5

内置类型函数的 Python 文档提供了有关类型(带有一个参数)和 isinstance 之间差异的明确指导。

使用一个参数,返回对象的类型。返回值是一个类型对象,通常与 object 返回的对象相同。班级。建议使用 isinstance() 内置函数来测试对象的类型,因为它考虑了子类。

为了说明这一点,请看一下模块 Diamond 中下面的继承层次结构:

在此输入图像描述

然后看一下下面基于diamond模块的python控制台输出:

在此输入图像描述

根据文档,它更加通用,可以覆盖更广泛的场景。关于OP的原始问题 - 性能特征没有被表述为支持其中一个而不是另一个的有效理由。可读性也不好。

要进行更深入的讨论,其中包括(用回答者的话说)“为什么在最近的 Python 版本中检查类型相等性是一种比以前更糟糕的做法”的解释,请参阅这个高度投票的答案