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

使用类型:

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()

当前回答

对于真正的差异,我们可以在代码中找到,但我找不到isinstance()默认行为的实现。

然而,我们可以得到类似的abc__instancecheck__根据__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

我得到这个结论,对于类型:

# 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)})

BTW:最好不要混用相对导入和绝对导入,使用project_dir中的绝对导入(由sys.path添加)

其他回答

type()和isinstance()之间的区别

type()->返回对象的类型

isinstance()->返回布尔值

一般来说,isinstance是一种“更”优雅的检查对象是否属于某种“类型”的方法(因为您知道继承链)。

另一方面,如果您不知道继承链,需要进行pick,请选择类型(x)==。。。

类型的另一个有趣的例子是检查bool

----Case bool----

print(type(True) == int) # False
print(type(False) == int) # False
print(type(True) == bool) # True
print(type(False) == bool) # True

print(isinstance(True, int)) # True
print(isinstance(True, int)) # True



----Case inheritance----
class A:
    x=1

class B(A):
    x=2

class C(B):
    x=3
    
var1 = A()
var2 = B()
var3 = C()

print(type(var1)) # <class '__main__.A'>
print(type(var1) == A) # True
print(type(var2) == A) # False
print(type(var3) == A) # False

print(isinstance(var1, A)) # True
print(isinstance(var2, A)) # True
print(isinstance(var3, A)) # True



print(type(var2)) # <class '__main__.B'>
print(type(var1) == B) # False
print(type(var2) == B) # True
print(type(var3) == B) # False

print(isinstance(var1, B)) # False
print(isinstance(var2, B)) # True
print(isinstance(var3, B)) # True



print(type(var3)) # <class '__main__.C'>
print(type(var1) == C) # False
print(type(var2) == C) # False
print(type(var3) == C) # True

print(isinstance(var1, C)) # False
print(isinstance(var2, C)) # False
print(isinstance(var3, C)) # True

Python中isinstance()和type()之间的区别?

类型检查方式

isinstance(obj, Base)

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

isinstance(obj, (Base1, Base2))

而类型检查

type(obj) is Base

仅支持引用的类型。


作为旁注,这可能比

type(obj) == Base

因为类是单独的。

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

在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对象可以从字典或记录中构造。在这种情况下,您的代码需要知道获取的参数类型,以便正确处理。

因此,要回答这个问题:

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,它是dict的子类(如果我们希望我们的代码遵循Liskov替换的原则,那么子类可以替换类型),我们的代码就会中断!:

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,我们可以支持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')]))

return OrderedDict([('fo','bar'),('fizz','buzz')])

抽象基类

事实上,我们可以做得更好。集合提供抽象基类,这些抽象基类为各种类型强制执行最小协议。在我们的情况下,如果我们只期望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

对评论的回应:

需要注意的是,类型可以用于使用(A,B,C)中的类型(obj)检查多个类

是的,您可以测试类型的相等性,但不要使用上述方法,而是使用控制流的多个基,除非您只允许这些类型:

isinstance(obj, (A, B, C))

不同之处再次在于,isinstance支持子类,这些子类可以替换父类而不破坏程序,这一特性称为Liskov替换。

但更好的是,颠倒依赖关系,根本不检查特定类型。

结论

因此,由于我们希望支持替换子类,在大多数情况下,我们希望避免使用类型进行类型检查,而更喜欢使用isinstance进行类型检查-除非您确实需要知道实例的精确类。

下面是一个例子,isinstance实现了类型无法实现的功能:

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.

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

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

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

if isinstance(b, (str, unicode)):
    do_something_else()

或者,使用basestring抽象类:

if isinstance(b, basestring):
    do_something_else()

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

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

因此,isinstance()应该优先于type()。