type()和isinstance()之间有什么区别?

时间:2009-10-11 03:50:55

标签: python oop inheritance types

这两个代码片段有什么区别? 使用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()

6 个答案:

答案 0 :(得分:1139)

总结其他(已经很好!)答案的内容,isinstance满足继承(派生类的实例也是基类的实例),而检查type的相等性是不是(它要求类型的标识并拒绝子类型的实例,AKA子类)。

通常,在Python中,你希望你的代码支持继承,当然(因为继承是如此方便,使用你的代码来阻止使用它的代码会很糟糕!),所以isinstance不如检查type的身份,因为它无缝地支持继承。

并不是isinstance ,请注意 - 它只是不那么糟糕而不是检查类型的相等性。正常的,Pythonic,首选解决方案几乎总是“鸭子打字”:尝试使用参数,好像它是某种所需的类型,在try / {{1}中执行如果参数实际上不属于那种类型(或任何其他类型很好地模仿它;-),并且在except子句中,尝试别的东西(使用参数“),可以捕获所有可能出现的异常好像“它是其他类型的。”

except ,但是,这是一个非常特殊的案例 - 内置类型,仅存在 ,可让您使用basestringisinstance 1}}和str子类unicode)。字符串是序列(你可以循环它们,索引它们,切片它们......),但你通常希望将它们视为“标量”类型 - 它有点不方便(但是一个相当频繁的用例)来处理各种类型的字符串(也许是其他标量类型,即你无法循环的那些)单向,所有容器(列表,集合,dicts,...)以另一种方式,basestringbasestring帮助你做到这一点 - 这个成语的整体结构是这样的:

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的更多信息,请参阅herehere [[第二部分]],特别是在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对于子类也是如此。

另见:How to compare type of an object in Python?

答案 2 :(得分:83)

  

Python中isinstance()type()之间的差异?

使用

进行类型检查
isinstance(obj, Base)

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

isinstance(obj, (Base1, Base2))

使用

进行类型检查
type(obj) is Base

仅支持引用的类型。


作为旁注,is可能比

更合适
type(obj) == Base

因为课程是单身。

避免类型检查 - 使用多态(duck-typing)

在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 记录构造。在这种情况下,您的代码需要知道它所获得的参数类型,以便它可以正确处理它。

所以,回答这个问题:

Python中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

TrueFalse只是在python中表示10的关键字。因此,

isinstance(True, int)

isinstance(False, int)

都返回True。两个布尔值都是整数的实例。 type()更聪明:

type(True) == int

返回False