Python isinstance(foo,bar)与type(foo)是bar

Python isinstance(foo,bar)与type(foo)是bar,python,typechecking,Python,Typechecking,一个语义问题,真的 直到最近,如果我必须对结构进行任何类型检查,我会使用type(obj)is list等。但是自从加入以来,我注意到每个人(我的意思是每个人)都使用isinstance(obj,list)。似乎它们是同义词,timeit揭示了它们之间几乎相同的速度 def a(): return type(list()) is list def b(): return isinstance(list(),list) from timeit import timeit timeit(a) #

一个语义问题,真的

直到最近,如果我必须对结构进行任何类型检查,我会使用
type(obj)is list
等。但是自从加入以来,我注意到每个人(我的意思是每个人)都使用
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
事实上,即使是
dis
也同意它们是同义词,除了
type is
COMPARE\u 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 
坦率地说,我发现说
如果type(foo)是list:
如果isinstance(foo,list):
更具可读性,第一个基本上只是伪代码,第二个调用一些带有参数的函数(我每次都要查找
isinstance
instanceof
)。它看起来不像类型转换,也没有明确的方法知道
isinstance(a,b)
是否正在检查
b
是否是
a
的实例,反之亦然

我从中了解到,我们使用
isinstance
,因为它更适合继承<代码>类型(ClassDerivedFromList)是列表将失败,而
是实例(ClassDerivedFromList,list)
将成功。但如果我在检查什么应该始终是基本对象,那么我在执行
类型是
时真正失去了什么

如果我在检查什么应该始终是基本对象,那么我在执行类型是时真正失去了什么


很好,你在你的问题中给出了完整的书面答案,所以你的答案是你什么都没有损失!唯一需要使用
isinstance()
的时候是检查给定类相对于另一个类的继承时,正如您所说和引用的那样
type()
仅用于检查实例是否完全属于给定的基本类型

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

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

您的问题的答案是:
不,考虑到您正在检查一个确定的基类,因为您失去了测试继承类的能力

IMO
isinstance
更易于阅读,在Python中:可读性很重要

PS:我在计时方面有了很大的不同(在Python3.3上)

对于类型(带有一个参数)和iInstance之间的差异,提供了明确的指导

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

为了进行说明,请查看模块diamond中下面的继承层次结构:

然后根据模块diamond查看下面的python控制台输出:

根据文档,它更通用,可以覆盖更广泛的场景。关于OP的原始问题——没有将性能特征作为一个优于另一个的有效理由。可读性也是如此

要进行更深入的讨论,其中包括解释(用回答者的话来说)“为什么在最近的Python版本中检查类型相等比以前更糟糕”,请参阅这个投票率很高的类型(x)不适用于mypy 至少对我来说,比起
type(x)
更喜欢
isinstance
的主要原因是mypy可以从
isinstance
检查中推断类型,但不能使用
type(x)
。从文档中:

使用isinstance类型时,Mypy通常可以正确推断类型 测试,但对于其他类型的检查,可能需要添加显式 类型转换:


来源:

我特别考虑重构一个我6个月前写的函数,该函数可以接受字符串或字符串列表。该函数的唯一输入将是
str
list
,如果type(foo)是str:\u handle\u str(foo)else:\u handle\u list(foo)
真的很糟糕吗?@adsmith:你使用Python 3吗?如果不是,那么如果你最后得到一个unicode字符串,你的代码就坏了。@DSM我知道,但我很欣赏
unicode
vs
str
。或者如果type(foo)是list:\u handle\u list(foo)else:\u handle\u str(foo)
,你也可以做
@DSM完全正确,要正确处理字符串,需要检查
isinstance(foo,basestring)
。如果我是你,我会检查
类型(foo)是否为list:\u handle\u list(foo)elif isinstance(foo,basestring):\u handle\u str(foo)else引发异常(“type Not Handled”)
。如果你比list更能容忍其他序列类型,你的lib将更容易被其他人采用,或者迁移到新的功能中,最著名的是元组和集合。接受生成器表达式代替列表也是一种前瞻性思维。您可以始终在(str,int)
中键入(x)。您发现
isinstance(foo,list)
type(foo)is list
更易于阅读。我很感谢您的回答,但你们在这里谈论的问题的唯一部分是我在我的问题中回答的。“我理解…我们使用
isinstance
是因为它更适合继承。
类型(ClassDerivedFromList)是list
将失败,而
isinstance(ClassDerivedFromList,list)
将成功”@AdamSmith-正如我在回答中指出的,文档清楚地解释了区别。“建议使用isinstance()内置函数来测试对象的类型,因为它考虑了子类。”我正在澄清您的不确定性,以及您为什么会注意到它是压倒性流行的选择。它更通用,可以覆盖更广泛的场景-type()在您知道确切类型的地方就足够了。我还希望用一些代码示例来说明这个答案,以进行澄清
      type: 0.5241982917936874  
isinstance: 0.46066255811928847
def f(o: object) -> None:
    if type(o) is int:
        o = cast(int, o)
        g(o + 1)    # This would be an error without the cast
        ...
    else:
        ...