这两个代码片段有什么区别?
使用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()
答案 0 :(得分:1139)
总结其他(已经很好!)答案的内容,isinstance
满足继承(派生类的实例也是基类的实例),而检查type
的相等性是不是(它要求类型的标识并拒绝子类型的实例,AKA子类)。
通常,在Python中,你希望你的代码支持继承,当然(因为继承是如此方便,使用你的代码来阻止使用它的代码会很糟糕!),所以isinstance
不如检查type
的身份,因为它无缝地支持继承。
并不是isinstance
好,请注意 - 它只是不那么糟糕而不是检查类型的相等性。正常的,Pythonic,首选解决方案几乎总是“鸭子打字”:尝试使用参数,好像它是某种所需的类型,在try
/ {{1}中执行如果参数实际上不属于那种类型(或任何其他类型很好地模仿它;-),并且在except
子句中,尝试别的东西(使用参数“),可以捕获所有可能出现的异常好像“它是其他类型的。”
except
,但是,这是一个非常特殊的案例 - 内置类型,仅存在 ,可让您使用basestring
(isinstance
1}}和str
子类unicode
)。字符串是序列(你可以循环它们,索引它们,切片它们......),但你通常希望将它们视为“标量”类型 - 它有点不方便(但是一个相当频繁的用例)来处理各种类型的字符串(也许是其他标量类型,即你无法循环的那些)单向,所有容器(列表,集合,dicts,...)以另一种方式,basestring
加basestring
帮助你做到这一点 - 这个成语的整体结构是这样的:
isinstance
您可以说if isinstance(x, basestring)
return treatasscalar(x)
try:
return treatasiter(iter(x))
except TypeError:
return treatasscalar(x)
是抽象基类(“ABC”) - 它没有为子类提供具体功能,而是作为“标记”存在,主要用于使用与basestring
。这个概念在Python中显然是一个不断增长的概念,因为PEP 3119引入了它的概括,并且已经被接受并且已经从Python 2.6和3.0开始实现。
PEP清楚地表明,尽管ABCs经常可以替代鸭子打字,但通常没有很大的压力(参见here)。然而,在最近的Python版本中实现的ABCs提供了额外的好处:isinstance
(和isinstance
)现在不仅仅意味着“[派生类的一个实例]”(特别是,任何类都可以使用ABC“注册”,以便它显示为子类,并将其实例显示为ABC的实例);通过模板方法设计模式应用程序,ABCs还可以非常自然的方式为实际的子类提供额外的便利(有关TM DP的更多信息,请参阅here和here [[第二部分]],特别是在Python中,独立于ABCs)。
对于Python 2.6中提供的ABC支持的基础机制,请参阅here;对于他们的3.1版本,非常相似,请参阅here。在这两个版本中,标准库模块collections(3.1版本 - 非常相似的2.6版本,请参阅here)提供了几个有用的ABC。
为了这个答案的目的,保留关于ABCs的关键(除了可以说更为自然的TM DP功能之外,与经典的Python替代方案如UserDict.DictMixin相比)是他们制作的issubclass
(和isinstance
)比以前更加有吸引力和普遍(在Python 2.6和前进中)(在2.5及之前),因此,相比之下,使检查类型相等为均匀最近的Python版本比以前更糟糕的做法。
答案 1 :(得分:303)
以下是isinstance
实现type
无法实现的内容的示例:
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
对于子类也是如此。
答案 2 :(得分:83)
Python中
isinstance()
和type()
之间的差异?
使用
进行类型检查isinstance(obj, Base)
允许子类的实例和多个可能的基础:
isinstance(obj, (Base1, Base2))
使用
进行类型检查type(obj) is Base
仅支持引用的类型。
作为旁注,is
可能比
type(obj) == Base
因为课程是单身。
在Python中,通常您希望允许任何类型的参数,按预期处理它,如果对象没有按预期运行,它将引发适当的错误。这被称为多态,也称为鸭子打字。
def function_of_duck(duck):
duck.quack()
duck.swim()
如果上面的代码有效,我们可以假设我们的论点是一个鸭子。因此我们可以传递其他东西是鸭子的实际子类型:
function_of_duck(mallard)
或像鸭子一样工作:
function_of_duck(object_that_quacks_and_swims_like_a_duck)
我们的代码仍然可以使用。
但是,在某些情况下,需要明确地进行类型检查。 也许你对不同的对象类型有明智的关系。例如,Pandas Dataframe对象可以从dicts 或记录构造。在这种情况下,您的代码需要知道它所获得的参数类型,以便它可以正确处理它。
所以,回答这个问题:
isinstance()
和type()
之间的差异?请允许我证明其中的区别:
type
假设您的函数获得某种参数(构造函数的常见用例),则需要确保某种行为。如果你检查这样的类型:
def foo(data):
'''accepts a dict to construct something, string support in future'''
if type(data) is not dict:
# we're only going to test for dicts for now
raise ValueError('only dicts are supported for now')
如果我们尝试传入一个作为dict
子类的字典(正如我们应该能够的话,如果我们希望我们的代码遵循Liskov Substitution的原则,那么子类型可以代替类型)我们的代码中断!:
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
,我们可以支持Liskov Substitution!:
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
提供了抽象基类,可以为各种类型强制执行最小协议。在我们的例子中,如果我们只期望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
应该注意,类型可以用于使用
检查多个类type(obj) in (A, B, C)
是的,您可以测试类型是否相等,但是除了上述内容之外,请使用多个基数来控制流,除非您特别只允许这些类型:
isinstance(obj, (A, B, C))
另一个区别是,isinstance
支持可以替换父类的子类,而不会破坏程序,这个属性称为Liskov替换。
但更好的是,反转您的依赖关系并且根本不检查特定类型。
因为我们想支持替换子类,在大多数情况下,我们希望避免使用type
进行类型检查,而更喜欢使用isinstance
进行类型检查 - 除非您确实需要知道精确的类一个实例。
答案 3 :(得分:59)
后者是首选,因为它将正确处理子类。实际上,您的示例可以更容易编写,因为isinstance()
的第二个参数可能是元组:
if isinstance(b, (str, unicode)):
do_something_else()
或使用basestring
抽象类:
if isinstance(b, basestring):
do_something_else()
答案 4 :(得分:12)
根据python文档,这里有一个声明:
8.15. types — Names for built-in types
从Python 2.2开始,内置 工厂功能,如
int()
和str()
也是 相应的类型。
所以isinstance()
应优先于type()
。
答案 5 :(得分:0)
实际用法上的区别在于它们如何处理booleans
:
True
和False
只是在python中表示1
和0
的关键字。因此,
isinstance(True, int)
和
isinstance(False, int)
都返回True
。两个布尔值都是整数的实例。 type()
更聪明:
type(True) == int
返回False
。