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

2022-09-05 00:53:34

这两个代码片段之间有什么区别?

使用类型

import types

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

使用等式

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

答案 1

为了总结其他(已经很好!)答案的内容,迎合继承(派生类的实例也是基类的实例),而检查的不等式不(它要求类型的标识并拒绝子类型,AKA子类的实例)。isinstancetype

通常,在Python中,你希望你的代码支持继承,当然(因为继承非常方便,所以停止使用你的代码使用它是不好的!),所以比检查s的身份要小,因为它无缝地支持继承。isinstancetype

请注意,这并不是好事 - 它只是比检查类型相等性更糟糕。正常的Pythonic首选解决方案几乎总是“鸭子类型”:尝试使用参数,就好像它是某种期望的类型一,在/语句中捕获如果参数实际上不是该类型(或任何其他类型很好地模仿它;-)可能出现的所有异常,并在子句中尝试其他方法(使用参数“好像”它是某种其他类型的)。isinstancetryexceptexcept

basestring 但是,这是一个非常特殊的情况 - 一个内置类型,它的存在只是为了让您使用(两者和子类)。字符串是序列(您可以循环访问它们,索引它们,切片它们,...),但是您通常希望将它们视为“标量”类型 - 以另一种方式处理所有类型的字符串(可能是其他标量类型,即您无法循环的字符串)有点不方便(但一个相当频繁的用例),所有容器(列表,集合,字典等)以另一种方式, plus可以帮助您做到这一点 - 这个成语的整体结构是这样的:isinstancestrunicodebasestringbasestringisinstance

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

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

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

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

为了这个答案的目的,保留ABC的关键事情(除了TM DP功能可以说更自然的位置,与UserDict.DictMixin等mixin类的经典Python替代品相比)是它们使(和)比以前(在2.5及之前)更具吸引力和普遍性,因为它们(在Python 2.6中及以后) 因此,相比之下,在最近的Python版本中,检查类型相等性比过去更糟糕。isinstanceissubclass


答案 2

下面是一个示例,其中实现了无法实现的目标:isinstancetype

class Vehicle:
    pass

class Truck(Vehicle):
    pass

在本例中,卡车对象是 Vehicle,但您将获得以下结果:

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中比较对象的类型?