python中的isinstance()和type()之间的区别

这两个代码段有什么区别? 哪种方式被认为是更pythonic?

使用type()

 import types if type(a) is types.DictType: do_something() if type(b) in types.StringTypes: do_something_else() 

使用isinstance()

 if isinstance(a, dict): do_something() if isinstance(b, str) or isinstance(b, unicode): do_something_else() 

编辑:这似乎已被讨论: 链接 。

总结其他(已经很好!)答案的内容, isinstance迎合inheritance(派生类的一个实例也是一个基类的一个实例),而检查type相等性不(它要求types的身份和拒绝亚型,AKA亚类的实例)。

通常,在Python中,你希望你的代码支持inheritance,当然(因为inheritance是如此的方便,使用你的代码停止代码是不好的!),所以isinstance比检查type s的身份差,因为它无缝地支持inheritance。

这不是说isinstance好的isinstance你 – 这比检查types的平等性要差 。 正常的Pythonic首选的解决scheme几乎总是“鸭子打字”:尝试使用这个参数,就好像它是某种期望的types一样,在try / except语句中捕获所有可能出现的exception,如果该参数实际上不是事实(或任何其他types的鸭子模仿它;-),并在except条款,尝试别的(使用参数“好像”它是其他types)。

basestring 一个相当特殊的情况 – 内buildtypes存在于isinstancestrUnicode子类basestring )中。 string是序列(你可以在它们上面循环,索引它们,切片,…),但是你通常想把它们当作“标量”types来处理 – 这样做有点不方便(但是相当频繁的用例)string(也可能是其他标量types,也就是你无法循环的标量types),所有容器(列表,集合,字典,…)以另一种方式, basestringisinstance可以帮助你做到这一点 – 整体结构这个成语是这样的:

 if isinstance(x, basestring) return treatasscalar(x) try: return treatasiter(iter(x)) except TypeError: return treatasscalar(x) 

你可以说basestring是一个抽象基类 (“ABC”) – 它没有为子类提供具体的function,而是作为一个“标记”存在,主要用于isinstance 。 这个概念在Python中显然是一个越来越大的概念,因为引入了概括性的PEP 3119被接受,并且已经从Python 2.6和3.0开始实现。

PEP明确指出,虽然ABCs通常可以代替鸭子打字,但通常没有很大的压力(见这里 )。 然而,在最近的Python版本中实现的ABCs却提供了额外的好处: isinstance (和issubclass )现在不仅仅意味着“派生类的实例”(特别是任何类都可以用ABC注册,它将显示为一个子类,其实例为ABC的实例); 而且ABCs也可以通过模板方法devise模式应用程序以一种非常自然的方式为实际的子类提供额外的便利(有关TM DP的更多信息,请参阅这里和这里 [部分II]],一般而言,特别是Python,独立于ABCs) 。

有关Python 2.6提供的ABC支持的基本机制,请参见此处 ; 对于他们的3.1版本,非常相似,请看这里 。 在这两个版本中,标准库模块集合 (这是3.1版本 – 非常类似的2.6版本,请参阅这里 )提供了几个有用的ABC。

对于这个答案来说,保留关于ABCs的关键是(比起像UserDict.DictMixin这样的mixin类的经典Python替代方法,TM TMfunction更加自然的位置),它们使得isinstance (和issubclass ) (在Python 2.6中并向前发展)远远超过以前(在2.5和之前),因此相比之下,在最近的Python版本中,检查types相等性是一种比以前更糟的做法。

这就是为什么isinstancetype更好:

 class Vehicle: pass class Truck(Vehicle): pass 

在这种情况下,卡车对象是一辆车,但你会得到这个:

 isinstance(Vehicle(), Vehicle) # returns True type(Vehicle()) == Vehicle # returns True isinstance(Truck(), Vehicle) # returns True type(Truck()) == Vehicle # returns False, and this probably won't be what you want. 

换句话说, isinstance也适用于子类。

另请参阅: 如何比较Python中的对象的types?

后者是首选,因为它会正确处理子类。 事实上,你的例子可以更容易编写,因为isinstance()的第二个参数可能是一个元组:

 if isinstance(b, (str, unicode)): do_something_else() 

或者,使用basestring抽象类:

 if isinstance(b, basestring): do_something_else() 

Python中isinstance()type()之间的区别?

使用types检查

 isinstance(obj, Base) 

允许子类和多个可能的基地的例子:

 isinstance(obj, (Base1, Base2)) 

而用types检查

 type(obj) == Base 

只支持引用的types。

避免使用types检查 – 使用多态性(鸭子打字)

在Python中,通常你想允许任何types的参数,如预期的那样对待它,如果对象的行为不如预期的那样,将会引发相应的错误。 这被称为多态性,也被称为鸭子打字。

 def function_of_duck(duck): duck.quack() duck.swim() 

如果上面的代码起作用,我们可以推定我们的论点是一个鸭子。 因此,我们可以通过其他的东西,鸭子的实际子types:

 function_of_duck(mallard) 

或者像鸭子一样工作:

 function_of_duck(object_that_quacks_and_swims_like_a_duck) 

而我们的代码仍然有效。

但是,在某些情况下,需要明确地进行types检查。 也许你对于不同的对象types有明智的做法。 例如,Pandas Dataframe对象可以由字典logging构build。 在这种情况下,你的代码需要知道它正在获取什么types的参数,以便它可以正确处理它。

所以,要回答这个问题:

Python中isinstance()type()之间的区别?

让我来certificate一下:

type

假如你的函数得到某种参数(构造函数的一个常见用例),你需要确保一定的行为。 如果你检查这样的types:

 def foo(data): '''accepts a dict to construct something, string support in future''' if type(data) != dict: # we're only going to test for dicts for now raise ValueError('only dicts are supported for now') 

如果我们试图传入一个dict的子类(如果我们希望我们的代码遵循Liskov Substitution的原则,那么这个子types可以被types替代),我们的代码就会中断!

 from collections import OrderedDict foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])) 

引发错误!

 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in foo ValueError: argument must be a dict 

isinstance

但是如果我们使用isinstance ,我们可以支持Liskovreplace!

 def foo(a_dict): if not isinstance(a_dict, dict): raise ValueError('argument must be a dict') return a_dict foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])) 

返回OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])

抽象基类

事实上,我们可以做得更好。 collections提供了对各种types实施最小协议的抽象基类。 在我们的例子中,如果我们只期望Mapping协议,我们可以做到以下几点,我们的代码变得更加灵活:

 from collections import Mapping def foo(a_dict): if not isinstance(a_dict, Mapping): raise ValueError('argument must be a dict') return a_dict 

结论

所以既然我们想支持替代子类,在大多数情况下,我们希望避免使用types进行types检查,并希望使用isinstancetypes检查 – 除非您确实需要知道实例的确切类别。

根据python文档这里是一个声明:

8.15。 types – 内置types的名称

从Python 2.2开始,内置的工厂函数(如int()str()也是相应types的名称。

所以isinstance()应该优于type()