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')
...
您的问题的答案是:
不,考虑到您正在检查一个确定的基类,因为您失去了测试继承类的能力
IMOisinstance
更易于阅读,在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
vsstr
。或者如果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:
...