代码之家  ›  专栏  ›  技术社区  ›  abbot

type()和isInstance()有什么区别?

  •  1054
  • abbot  · 技术社区  · 15 年前

    这两个代码片段之间有什么区别? 使用 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 回复  |  直到 6 年前
        1
  •  1103
  •   Uyghur Lives Matter    7 年前

    总结其他(已经很好了!)答案, isinstance 提供继承(派生类的实例 是一个 同时检查是否相等 type 不需要(它要求类型的标识并拒绝子类型的实例,也就是子类)。

    当然,在Python中,您通常希望您的代码支持继承(因为继承非常方便,所以最好不要让代码使用您的继承!)如此 实例 比检查的身份差 类型 因为它无缝地支持继承。

    不是那样的 实例 好的 注意,这只是 不差 而不是检查类型的相等性。正常的、蟒蛇式的、首选的解决方案几乎总是“鸭式打字”:尝试使用参数 犹如 它是某种理想的类型,用 try / except 捕捉所有可能出现的异常的语句,如果参数实际上不是该类型(或任何其他类型很好地模拟它;-),并且 除了 子句,尝试其他方法(使用参数“好像”它是其他类型的)。

    basestring 但是,相当特殊的情况是存在的内置类型 只有 让你使用 实例 (两者) str unicode 子类 基带 )字符串是序列(您可以循环它们,索引它们,切片它们,…),但是您通常希望将它们视为“标量”类型它有点不方便(但是一个相当频繁的用例)以一种方式处理所有类型的字符串(可能还有其他标量类型,即您不能循环的类型),在ano中处理所有容器(列表、集合、dict,…)顺便说一句, 基带 实例 帮助你做到这一点。这个成语的总体结构如下:

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

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

    政治公众人物清楚地表明,虽然ABC通常可以代替鸭子打字,但一般来说,这样做没有很大的压力(见 here )但是,在最近的python版本中实现的abc确实提供了额外的好处: 实例 (和) issubclass )现在可以不仅仅是“派生类的一个实例”(特别是,任何类都可以在ABC中“注册”,这样它将显示为一个子类,其实例将显示为ABC的实例);ABC还可以通过模板方法设计模式应用程序以非常自然的方式为实际子类提供额外的便利(请参见 here here [第二部分]]了解更多关于tm-dp的信息,一般情况下,尤其是在python中,独立于abc)。

    有关Python2.6中提供的ABC支持的底层机制,请参见 here ;对于3.1版本,非常相似,请参见 here .在两个版本中,标准库模块 collections (这是3.1版本对于非常相似的2.6版本,请参见 here )提供几种有用的ABC。

    为了回答这个问题,与传统的python混合类(如 UserDict.DictMixin )是他们做的吗 实例 (和) 子类 )比以前(在2.5及之前)更具吸引力和普及性(在python 2.6及以后的版本中),因此,相比之下,在最近的python版本中,检查类型相等性比以前更糟糕。

        2
  •  287
  •   Community CDub    8 年前

    这就是为什么 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.
    

    换言之, 实例 对于子类也是这样。

    另请参见: How to compare type of an object in Python?

        3
  •  78
  •   Aaron Hall    6 年前

    之间的差异 isinstance() type() 在蟒蛇?

    类型检查方式

    isinstance(obj, Base)
    

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

    isinstance(obj, (Base1, Base2))
    

    而类型检查

    type(obj) is Base
    

    仅支持引用的类型。


    作为旁白, is 可能比

    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)
    

    我们的代码仍然有效。

    但是,在某些情况下,需要显式地进行类型检查。 也许您对不同的对象类型有一些明智的做法。例如,可以从dicts构造pandas数据帧对象 记录。在这种情况下,您的代码需要知道它得到的参数类型,以便它能够正确地处理它。

    所以,要回答这个问题:

    之间的差异 ISSN() 类型() 在蟒蛇?

    请允许我演示一下区别:

    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 (如果我们希望代码遵循 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

    但是如果我们使用 实例 我们可以支持李斯科夫的替代!:

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

    不同之处在于 实例 支持在不破坏程序的情况下可以替换父类的子类,这是一个名为liskov substitution的属性。

    不过,更好的方法是反转依赖项,根本不检查特定类型。

    结论

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

        4
  •  58
  •   Esparta Palma John Millikin    11 年前

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

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

    或者,使用 basestring 抽象类:

    if isinstance(b, basestring):
        do_something_else()
    
        5
  •  11
  •   Grijesh Chauhan Anand Krishnan    11 年前

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

    8.15. types — Names for built-in types

    从python 2.2开始,内置 工厂功能,如 int() str() 也是 相应的类型。

    所以 isinstance() 应该优先于 type() .

        6
  •  0
  •   Cheney    7 年前

    对于真正的差异,我们可以在 code 但我找不到 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
    

    我得出这个结论, 为了 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)})
    

    顺便说一句:最好不要混用 relative and absolutely import 使用 absolutely import 来自项目目录(由添加 sys.path )