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

abb*_*bot 1163 python oop inheritance types

这两个代码片段之间有什么区别?使用type():

import types

if type(a) is types.DictType:
    do_something()
if type(b) in types.StringTypes:
    do_something_else()
Run Code Online (Sandbox Code Playgroud)

使用isinstance():

if isinstance(a, dict):
    do_something()
if isinstance(b, str) or isinstance(b, unicode):
    do_something_else()
Run Code Online (Sandbox Code Playgroud)

Ale*_*lli 1191

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

通常,在Python中,你希望你的代码支持继承,当然(因为继承非常方便,使用你的代码来阻止使用它的代码会很糟糕!),因此isinstance它比检查types的身份更糟糕,因为它无缝支持遗产.

这并不是说isinstance不错的,你要知道,它只是不那么糟糕不是检查的类型平等.正常的,Pythonic,首选解决方案几乎总是"鸭子打字":尝试使用该参数,就好像它是某种期望的类型一样,在try/ except语句中执行它,捕获可能出现的所有异常,如果参数实际上并非如此类型(或任何其他类型很好地模仿它;-),并在该except子句中,尝试其他东西(使用参数"好像"它是一些其他类型).

basestring ,但是,相当多的特殊情况,一个内建存在类型让你使用isinstance(包括strunicode子类basestring).字符串是序列(你可以循环它们,索引它们,切片它们......),但你通常希望将它们视为"标量"类型 - 它有点不方便(但是一个相当频繁的用例)来处理各种类型的字符串(也许是其他标量类型,即你不能循环的那些)单向,所有容器(列表,集合,dicts,...)以另一种方式,并且basestring加上isinstance帮助你做到这一点 - 这个的整体结构成语是这样的:

if isinstance(x, basestring)
  return treatasscalar(x)
try:
  return treatasiter(iter(x))
except TypeError:
  return treatasscalar(x)
Run Code Online (Sandbox Code Playgroud)

你可以说这basestring是一个抽象基类("ABC") - 它没有提供子类的具体功能,而是作为"标记"存在,主要用于isinstance.这个概念在Python中显然是一个不断增长的概念,因为PEP 3119引入了它的概括,它已经被接受并且已经从Python 2.6和3.0开始实现.

PEP清楚地表明,虽然ABCs经常可以替代鸭子打字,但通常没有很大的压力(见这里).然而,在最近的Python版本中实现的ABCs提供了额外的好处:( isinstanceissubclass)现在不仅仅意味着"[派生类的一个实例]"(特别是,任何类都可以用ABC"注册",这样就可以了显示为子类,其实例作为ABC的实例); 和ABC还可以通过模板方法设计模式应用程序以非常自然的方式为实际的子类提供额外的便利(有关TM DP的更多信息,请参见此处和[ 此处 [[第II部分]],一般而言,特别是在Python中,独立于ABCs) .

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

出于这个答案的目的,保留关于ABCs的关键(除了可以说更自然的TM DP功能放置,与混合类的经典Python替代方案,如UserDict.DictMixin)是他们制作isinstance(和issubclass)更多有吸引力和普遍的(在Python 2.6和前进中)比以前(在2.5和之前),因此,相比之下,使检查类型相等在最近的Python版本中比以前更糟糕的做法.

  • “请注意,并不是实例很好,它没有检查类型相等性那么坏。正常的,Python式的首选解决方案几乎总是“鸭式输入”。这是一个相当有限的视图:例如,在解释器中使用isinstance()的*情况非常好,其中类型反映了语法。成为“ Pythonic”并不是一切! (4认同)
  • 当没有目标时,我永远无法理解形容词_更好_和_更差_。如果你不知道它的用途,那怎么可能会_更好_呢?如果您也不想检查子类,则 `isinstance` __not__ 更好。它只是做了一件不同的事情。 (4认同)
  • basestring 在 Python 3 中不可用。 (2认同)
  • @EduardoPignatelli:对于像这样的主观用途,“更好”实际上只是意味着“当您没有充分的理由更喜欢特定方法时,这应该是默认值?”。在这里,如果您没有排除子类的已知要求,即使您不知道要处理的任何子类,也默认为“isinstance”,因为如果第三方使用您的代码,它更有可能起作用想要传递您所识别的类型的自己的子类;如果子类违反了期望,它*可能*不起作用,但如果您根本拒绝处理子类,它*肯定*不会起作用。 (2认同)

Pet*_*ter 318

这就是为什么isinstance比以下更好type:

class Vehicle:
    pass

class Truck(Vehicle):
    pass
Run Code Online (Sandbox Code Playgroud)

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

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.
Run Code Online (Sandbox Code Playgroud)

换句话说,isinstance对于子类也是如此.

另请参阅:如何在Python中比较对象的类型?

  • 因为在某种情况下你不想要isInstance行为,我认为没有"更好".他们只是做了不同的事情. (136认同)
  • -1,因为"isinstance比type更好"是一个误导性的评论.它被理解为"`type`已被弃用,乍看之下使用`isinstance`代替".例如,我想要的只是`type()`检查,但由于这个原因我被误导了很短的时间(并且必须调试一点). (23认同)
  • 这是他们如何以不同方式工作的一个很好的例子,但我遇到了一个特别需要`type()`而不是`isinstance()`的情况.一个不是更好; 他们是为了不同的事情. (7认同)
  • 请你告诉我 - 为什么你使用 == 而不是使用“is”? (2认同)

Aar*_*all 91

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

使用类型检查

isinstance(obj, Base)
Run Code Online (Sandbox Code Playgroud)

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

isinstance(obj, (Base1, Base2))
Run Code Online (Sandbox Code Playgroud)

而使用.进行类型检查

type(obj) is Base
Run Code Online (Sandbox Code Playgroud)

仅支持引用的类型.


作为旁注,is可能比更合适

type(obj) == Base
Run Code Online (Sandbox Code Playgroud)

因为班级是单身人士.

避免类型检查 - 使用多态性(鸭子打字)

在Python中,通常您希望允许任何类型的参数,按预期处理它,如果对象没有按预期运行,它将引发适当的错误.这被称为多态,也称为鸭子打字.

def function_of_duck(duck):
    duck.quack()
    duck.swim()
Run Code Online (Sandbox Code Playgroud)

如果上面的代码有效,我们可以假设我们的论点是一个鸭子.因此我们可以传递其他东西是鸭子的实际子类型:

function_of_duck(mallard)
Run Code Online (Sandbox Code Playgroud)

或者像鸭子一样工作:

function_of_duck(object_that_quacks_and_swims_like_a_duck)
Run Code Online (Sandbox Code Playgroud)

我们的代码仍然有效.

但是,在某些情况下需要明确地进行类型检查.也许你对不同的对象类型有明智的关系.例如,Pandas Dataframe对象可以从dicts 记录构造.在这种情况下,您的代码需要知道它所获得的参数类型,以便它可以正确处理它.

那么,回答这个问题:

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

请允许我证明一下差异:

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')
Run Code Online (Sandbox Code Playgroud)

如果我们尝试传入一个dict,它是一个子类dict(我们应该可以,如果我们希望我们的代码遵循Liskov Substitution的原则,那个子类型可以代替类型)我们的代码中断了!:

from collections import OrderedDict

foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))
Run Code Online (Sandbox Code Playgroud)

提出错误!

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

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')]))
Run Code Online (Sandbox Code Playgroud)

回报 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
Run Code Online (Sandbox Code Playgroud)

回复评论:

应该注意,类型可以用于检查多个类使用 type(obj) in (A, B, C)

是的,您可以测试类型是否相等,但是除了上述内容之外,使用多个基数来控制流,除非您特别只允许这些类型:

isinstance(obj, (A, B, C))
Run Code Online (Sandbox Code Playgroud)

不同的是,isinstance支持子类可以替代父类而不会破坏程序,这个属性称为Liskov替换.

但是,更好的是,反转你的依赖关系并且根本不检查特定的类型.

结论

因此,由于我们想要支持替换子类,在大多数情况下,我们希望避免使用类型检查type并且更喜欢使用isinstance- 而不是确实需要知道实例的精确类.


Joh*_*kin 63

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

if isinstance(b, (str, unicode)):
    do_something_else()
Run Code Online (Sandbox Code Playgroud)

或者,使用basestring抽象类:

if isinstance(b, basestring):
    do_something_else()
Run Code Online (Sandbox Code Playgroud)


Ale*_*ine 16

实际用法的区别在于它们的处理方式booleans

True并且False只是在python中表示1和的关键字0。因此,

isinstance(True, int)
Run Code Online (Sandbox Code Playgroud)

isinstance(False, int)
Run Code Online (Sandbox Code Playgroud)

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

type(True) == int
Run Code Online (Sandbox Code Playgroud)

返回False


Xin*_*nus 14

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

8.15.types - 内置类型的名称

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

所以isinstance()应该优先考虑type().