问题:type()和isinstance()有什么区别?
这两个代码片段之间有什么区别?
使用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
总结其他(已经很好!)答案的内容,isinstance
迎合继承(派生类的实例也是基类的实例),而检查的相等性type
则不(要求类型的标识并拒绝实例)子类型,又称为AKA子类)。
通常,在Python中,当然,您希望您的代码支持继承(由于继承非常方便,因此停止使用您的代码来使用它会很糟糕!),这isinstance
比检查type
s的身份要糟糕得多,因为它无缝地支持s遗产。
这并不是说isinstance
是不错的,你要知道,它只是不那么糟糕不是检查的类型平等。正常的,Python式的首选解决方案几乎总是“鸭式输入”:尝试使用参数,就好像它是某个所需的类型一样,在try
/ except
语句中进行处理,以捕获如果参数实际上不是该参数可能会出现的所有异常类型(或其他可以模仿它的其他类型;-),然后在except
子句中尝试其他操作(使用参数“好像”是其他类型)。
basestring
是,但是,相当多的特殊情况,一个内建存在类型只让你使用isinstance
(包括str
和unicode
子类basestring
)。字符串是序列(您可以对它们进行循环,对其进行索引,对其进行切片等),但是您通常希望将它们视为“标量”类型-处理各种类型的字符串有点不方便(但在相当频繁的情况下)字符串(可能还有其他标量类型,即您不能循环的类型),所有容器(列表,集合,字典,…)的另一种方法,basestring
加上这些isinstance
可以帮助您做到这一点–总体结构成语是这样的:
if isinstance(x, basestring)
return treatasscalar(x)
try:
return treatasiter(iter(x))
except TypeError:
return treatasscalar(x)
您可以说这basestring
是一个抽象基类(“ ABC”)-它没有为子类提供具体功能,而是作为“标记”存在,主要用于isinstance
。自从引入PEP 3119(引入了它的概括)以来,该概念显然在Python中正在不断发展。自从PEP 3119以来,该概念已从Python 2.6和3.0开始实施。
PEP清楚地表明,尽管ABC通常可以代替鸭类打字,但这样做通常没有很大的压力(请参见此处)。但是,在最新的Python版本中实现的ABC确实提供了额外的好处:(isinstance
和issubclass
)现在的含义不仅仅是“派生类的一个实例”(特别是,任何类都可以在ABC中“注册”,以便它可以显示为子类,其实例显示为ABC实例);并且ABC还可以通过模板方法设计模式应用程序以一种非常自然的方式为实际子类提供额外的便利(有关TM DP的更多信息,请参见此处和此处的 [[Part II]],有关Python的更多信息,特别是在Python中,与ABC无关) 。
有关Python 2.6中提供的ABC支持的基本机制,请参见此处;其3.1版本非常相似,请参见此处。在这两个版本中,标准库模块集合(即3.1版本,对于非常相似的2.6版本,请参见此处)都提供了一些有用的ABC。
出于这个答案的目的,保留ABC的关键是(与TM DP混合类的经典Python替代类(例如UserDict.DictMixin相比,TM DP功能可以说是更自然的放置))是它们使isinstance
(和issubclass
)具有更多优势(在Python 2.6及更高版本中)比以前(在2.5及更低版本中)更具吸引力和普遍性,因此,相比之下,使类型相等性检查在最近的Python版本中比以前更加糟糕。
回答 1
这是一个无法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
对于子类也是如此。
另请参阅:如何在Python中比较对象的类型?
回答 2
isinstance()
和type()
Python 之间的区别?
进行类型检查
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对象可以由字典或记录构造。在这种情况下,您的代码需要知道它获取的参数类型,以便它可以正确处理它。
所以,要回答这个问题:
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')
如果我们尝试传递dict
作为的子类的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替换!:
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
首选后者,因为它将正确处理子类。实际上,由于isinstance()
的第二个参数可能是元组,因此您的示例编写起来甚至更加容易:
if isinstance(b, (str, unicode)):
do_something_else()
或者,使用basestring
抽象类:
if isinstance(b, basestring):
do_something_else()
回答 4
根据python文档,这是一条语句:
8.15。类型-内置类型的名称
从Python 2.2开始,内置的工厂函数(例如
int()
和)str()
也是相应类型的名称。
所以isinstance()
应该优先于type()
。
回答 5
实际用法的区别在于它们如何处理booleans
:
True
而False
只是关键字,平均1
和0
Python编写的。从而,
isinstance(True, int)
和
isinstance(False, int)
都回来了True
。两个布尔值都是整数的实例。type()
但是,它更聪明:
type(True) == int
返回False
。
回答 6
对于真正的差异,我们可以在中找到它code
,但我找不到的默认行为的实现isinstance()
。
但是,我们可以根据__instancecheck__获得类似的abc .__ instancecheck__。
从上方abc.__instancecheck__
,使用以下测试后:
# file tree
# /test/__init__.py
# /test/aaa/__init__.py
# /test/aaa/aa.py
class b():
pass
# /test/aaa/a.py
import sys
sys.path.append('/test')
from aaa.aa import b
from aa import b as c
d = b()
print(b, c, d.__class__)
for i in [b, c, object]:
print(i, '__subclasses__', i.__subclasses__())
print(i, '__mro__', i.__mro__)
print(i, '__subclasshook__', i.__subclasshook__(d.__class__))
print(i, '__subclasshook__', i.__subclasshook__(type(d)))
print(isinstance(d, b))
print(isinstance(d, c))
<class 'aaa.aa.b'> <class 'aa.b'> <class 'aaa.aa.b'>
<class 'aaa.aa.b'> __subclasses__ []
<class 'aaa.aa.b'> __mro__ (<class 'aaa.aa.b'>, <class 'object'>)
<class 'aaa.aa.b'> __subclasshook__ NotImplemented
<class 'aaa.aa.b'> __subclasshook__ NotImplemented
<class 'aa.b'> __subclasses__ []
<class 'aa.b'> __mro__ (<class 'aa.b'>, <class 'object'>)
<class 'aa.b'> __subclasshook__ NotImplemented
<class 'aa.b'> __subclasshook__ NotImplemented
<class 'object'> __subclasses__ [..., <class 'aaa.aa.b'>, <class 'aa.b'>]
<class 'object'> __mro__ (<class 'object'>,)
<class 'object'> __subclasshook__ NotImplemented
<class 'object'> __subclasshook__ NotImplemented
True
False
我得到以下结论type
:
# according to `abc.__instancecheck__`, they are maybe different! I have not found negative one
type(INSTANCE) ~= INSTANCE.__class__
type(CLASS) ~= CLASS.__class__
对于isinstance
:
# guess from `abc.__instancecheck__`
return any(c in cls.__mro__ or c in cls.__subclasses__ or cls.__subclasshook__(c) for c in {INSTANCE.__class__, type(INSTANCE)})
顺便说一句:最好不要混用use relative and absolutely import
,而要使用absolutely import
project_dir(由添加sys.path
)