这两个代码片段之间有什么区别?使用 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 回答
这就是
isinstance
优于type
的原因:在这种情况下,卡车对象是一辆车,但你会得到这个:
换句话说,
isinstance
也适用于子类 .另见:How to compare type of an object in Python?
对于真正的差异,我们可以在
code
中找到它,但是我找不到isinstance()
的默认行为的实现 .但是我们可以根据instancecheck获得类似的abc.instancecheck .
从
abc.__instancecheck__
以上,使用下面的测试:我得到了这个结论,对于
type
:对于
isinstance
:BTW:最好不要混用
relative and absolutely import
,使用project_dir中的absolutely import
(由sys.path
添加)根据python文档,这里有一个声明:
所以isinstance()应优先于type() .
总结其他(已经很好!)答案的内容,
isinstance
迎合继承(派生类的实例也是基类的实例),而检查type
的相等性则不然(它需要类型的身份和拒绝子类型的实例,AKA子类) .通常,在Python中,你希望你的代码支持继承,当然(因为继承非常方便,使用你的代码来阻止使用它的代码会很糟糕!),所以
isinstance
比检查type
的标识要糟糕得多,因为它无缝地支持继承 .并不是说
isinstance
是好的,请注意 - 它比检查类型的相等性要差 . 正常的,Pythonic,首选解决方案几乎总是"duck typing":尝试使用该参数,就好像它是某种所需类型一样,在try
/except
语句中执行它,捕获可能出现的所有异常,如果参数实际上不属于该类型(或任何其他类型很好地模仿它;-),并在except
子句中,尝试其他东西(使用参数"as if"它是其他类型的) .basestring
is ,但是,非常特殊的情况 - 存在 only 的内置类型,让您使用isinstance
(str
和unicode
子类basestring
) . 字符串是序列(你可以循环它们,索引它们,切片它们......),但你通常希望将它们视为"scalar"类型 - 它's somewhat incovenient (but a reasonably frequent use case) to treat all kinds of strings (and maybe other scalar types, i.e., ones you can't循环)单向,所有容器(列表,集合,dicts, ...)以另一种方式,basestring
加上isinstance
帮助你做到这一点 - 这个成语的整体结构是这样的:你可以说
basestring
是一个抽象基类("ABC") - 它没有为子类提供具体的功能,而是作为"marker"存在,主要用于isinstance
. 这个概念在Python中显然是一个不断增长的概念,因为PEP 3119引入了它的概括,它被接受并且已经从Python 2.6和3.0开始实现 .PEP清楚地表明,虽然ABCs通常可以替代鸭子打字,但通常没有很大的压力(见here) . 然而,在最近的Python版本中实现的ABCs提供了额外的好处:
isinstance
(和issubclass
)现在不仅仅意味着"[an instance of] a derived class"(特别是,任何类都可以是带有ABC的"registered",因此它将显示为子类,其实例为ABC的实例);通过模板方法设计模式应用程序,ABCs还可以非常自然的方式为实际的子类提供额外的便利(有关TM DP的更多信息,请参阅here和here [[part II]],一般而言,特别是在Python中,独立于ABCs) .有关Python 2.6中提供的ABC支持的基础机制,请参阅here;对于他们的3.1版本,非常相似,请参阅here . 在这两个版本中,标准库模块collections(这是3.1版本 - 非常相似的2.6版本,请参阅here)提供了几个有用的ABC .
出于这个答案的目的,保留关于ABCs的关键(除了可以说更加自然的TM DP功能放置,与混合类的经典Python替代方案,如UserDict.DictMixin相比),它们更多地使
isinstance
(和issubclass
)更多有吸引力和普遍的(在Python 2.6和前进中)比以前(在2.5和之前),因此,相比之下,使检查类型相等在最近的Python版本中比以前更糟糕的做法 .使用类型检查
允许子类的实例和多个可能的基础:
而使用 . 进行类型检查
仅支持引用的类型 .
作为旁注,
is
可能比更合适因为 class 是单身人士 .
避免类型检查 - 使用多态性(鸭子打字)
在Python中,通常您希望允许任何类型的参数,按预期处理它,如果对象没有按预期运行,它将引发适当的错误 . 这称为多态,也称为鸭子打字 .
如果上面的代码有效,我们可以假设我们的参数是一个鸭子 . 因此我们可以传入其他东西是鸭子的实际子类型:
或者像鸭子一样工作:
我们的代码仍然有效 .
但是,在某些情况下需要明确地进行类型检查 . 也许你对不同的对象类型有明智的关系 . 例如,Pandas Dataframe对象可以从dicts或记录构造 . 在这种情况下,您的代码需要知道它所获得的参数类型,以便它可以正确处理它 .
那么,回答这个问题:
Python中的isinstance()和type()之间的区别?
请允许我展示一下差异:
类型
假设您的函数获得某种参数(构造函数的常见用例),则需要确保某种行为 . 如果你检查这样的类型:
如果我们尝试传入一个
dict
的子类的dict(我们应该可以,如果我们期望我们的代码遵循Liskov Substitution的原则,那个子类型可以代替类型)我们的代码会破坏!:提出错误!
isinstance
但是如果我们使用
isinstance
,我们可以支持Liskov Substitution!:返回
OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])
抽象基类
事实上,我们可以做得更好 .
collections
提供了为各种类型强制执行最小协议的抽象基类 . 在我们的例子中,如果我们只期望Mapping
协议,我们可以执行以下操作,并且我们的代码变得更加灵活:回复评论:
是的,你可以测试类型的相等性,但是除了上面的内容之外,使用多个基数来控制流,除非你特别只允许这些类型:
不同的是,
isinstance
支持可替代父类的子类,而不会破坏程序,这是一种称为Liskov替换的属性 .但是,更好的是,反转您的依赖项,而不是检查特定类型 .
结论
因此,由于我们想要支持替换子类,在大多数情况下,我们希望避免使用
type
进行类型检查,而更喜欢使用isinstance
进行类型检查 - 除非您确实需要知道实例的精确类 .后者是首选,因为它将正确处理子类 . 事实上,你的例子可以更容易编写,因为
isinstance()
的第二个参数可能是一个元组:或者,使用
basestring
抽象类: