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()
解决办法

总结一下其他 (已经很好了!) 答案的内容,isinstance满足了继承的要求 (一个派生类的实例也是一个基类的实例),而检查type的平等性则不然 (它要求类型的身份,拒绝子类型的实例,也就是子类)。

通常,在Python中,你当然希望你的代码支持继承(既然继承如此方便,那么阻止使用你的代码使用它就不好了!),所以isinstance比检查type的身份更不好,因为它无缝地支持继承。

这并不是说isinstance是_好的,你要知道--它只是比检查类型的平等性_更不坏。 正常的,Pythonic的,首选的解决方案是"duck typing"。 试着使用参数_好像它是某一类型,在 "try"/"except "语句中进行,捕捉所有可能出现的异常,如果参数事实上不是该类型(或任何其他类型,很好地模仿它;-),在 "except "子句中,尝试其他东西(使用参数"好像" 它是其他类型的)。)

然而,basestring的,是一个相当特殊的情况--一个内置的类型,它的存在**只是为了让你使用isinstancestrunicode都是basestring的子类)。 字符串是序列(你可以在它们上面循环、索引、切分它们,......),但你通常想把它们当作"标量&quot。 类型--用一种方式处理所有类型的字符串(也许还有其他标量类型,即那些你不能循环的类型),用另一种方式处理所有的容器(list、set、dicts......),有点不方便(但这是一个很常见的用例),而basestring加上isinstance可以帮助你做到这一点--这个成语的整体结构是这样的。

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

你可以说basestring是一个抽象基类 ("ABC")--它没有为子类提供具体的功能,而是作为一个"标记"而存在,主要用于isinstance。 这个概念在Python中显然是一个不断发展的概念,因为引入它的通用化的[PEP 3119][1]被接受,并从Python 2.6和3.0开始实现。

PEP明确指出,虽然ABCs经常可以替代鸭式输入法,但一般来说没有太大的压力(参见[这里][2])。 然而,在最近的 Python 版本中实现的 ABC 确实提供了额外的好东西。 isinstance (和issubclass)现在不仅仅意味着 "[一个实例]派生类&quot。 (特别是,任何类都可以用"注册&quot。 注册,这样它就会显示为一个子类,而它的实例则显示为ABC的实例)。) 而ABC也可以通过模板方法设计模式的应用,以一种非常自然的方式为实际的子类提供额外的便利(关于TM DP的更多内容,请参见[这里][3]和[这里][4][[第二部分]],在Python中一般地和具体地,独立于ABC)。

关于Python 2.6中提供的ABC支持的底层机制,参见[这里][5]。 关于它们的 3.1 版本,非常相似,参见 [这里][6]。 在这两个版本中,标准库模块[collections]7提供了几个有用的ABC。

为了这个答案的目的,保留 ABCs 的关键之处 (除了可以说是 TM DP 功能更自然的位置之外,与经典的 Python 替代品 mixin 类,如 [UserDict.DictMixin][9]相比),它们使 isinstance(和issubclass)比过去 (在 2.5 和之前) 更有吸引力和更普遍 (在 Python 2.6 和未来),因此,相比之下,在最近的 Python 版本中,检查类型平等比过去更糟糕。

[1]: http://www.python.org/dev/peps/pep-3119/ [2]: http://www.python.org/dev/peps/pep-3119/#abcs-vs-duck-typing [3]: http://en.wikipedia.org/wiki/Template_method_pattern [4]: http://www.catonmat.net/blog/learning-python-design-patterns-through-video-lectures/ [5]: http://docs.python.org/library/abc.html [6]: http://docs.python.org/3.1/library/abc.html [7]: http://docs.python.org/3.1/library/collections.html#module-collections [8]: http://docs.python.org/library/collections.html#module-collections [9]: http://docs.python.org/library/userdict.html?highlight=userdict#UserDict.DictMixin

评论(3)

这里有一个例子,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对子类也是真的。

也请看:

评论(6)

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

类型检查

isinstance(obj, Base)

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

isinstance(obj, (Base1, Base2))

而用

type(obj) is Base

只支持被引用的类型。


顺便说一句,"是 "可能比 "是 "更合适。

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对象可以由dicts记录构造。 在这种情况下,你的代码需要知道它得到的是什么类型的参数,这样才能正确处理它。

所以,回答这个问题。

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 Substitution][1]的原则,即子类型可以被替换成类型的话,我们应该可以做到这一点),我们的代码就会崩溃。

from collections import OrderedDict

foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))

引起一个错误!

Traceback (most recent call last):
  File "", line 1, in 
  File "", line 3, in foo
ValueError: argument must be a dict

Traceback (most recent call last):
  File "", line 1, in 
  File "", line 3, in foo
ValueError: argument must be a dict

isinstance

但是如果我们使用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')]))

返回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 "进行类型检查--除非你真的需要知道一个实例的精确类。

[1]: http://en.wikipedia.org/wiki/Liskov_substitution_principle

评论(1)

后者是首选,因为它能正确处理子类。事实上,你的例子可以写得更简单,因为isinstance()'的第二个参数可以是一个元组。

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

或者,使用basestring抽象类。

if isinstance(b, basestring):
    do_something_else()
评论(0)

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

8.15. types - Names for built-in types

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

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

评论(0)

实际使用上的区别是它们如何处理 "booleans"。

"True "和 "False "只是关键字,在python中表示 "1 "和 "0"。 因此:

isinstance(True, int)

isinstance(False, int)

都返回 "True"。 两个booleans都是一个整数的实例。 然而,type()更聪明。

type(True) == int

返回 "False"。

评论(0)

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

不过我们可以根据abc._/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))


 __subclasses__ []
 __mro__ (, )
 __subclasshook__ NotImplemented
 __subclasshook__ NotImplemented
 __subclasses__ []
 __mro__ (, )
 __subclasshook__ NotImplemented
 __subclasshook__ NotImplemented
 __subclasses__ [..., , ]
 __mro__ (,)
 __subclasshook__ NotImplemented
 __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)})

另外。 最好不要混用 "relative "和 "absolutely import",使用 "absolutely import "从project_dir(由sys.path添加的)

评论(0)