ChatGPT解决这个技术问题 Extra ChatGPT

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()
注意:如果不是 strunicode(您可以只检查 basestring),您可以使用元组来检查多种类型。要检查 somethingint 还是 str,请使用 isinstance(something, (int, str))
type() 返回您作为参数输入的对象的类型,除非与实际类型(例如 type(9) == int)进行比较,否则通常没有用处。 isinstance() 根据对象是否为给定类型返回布尔值 - true 或 false。在大多数情况下,isinstance 通常使用起来更优雅,而不是编写混乱的相等检查。

U
Uyghur Lives Matter

总结其他(已经很好!)答案的内容,isinstance 迎合继承(派生类的实例也是基类的实例),同时检查 { 2} 没有(它要求类型的标识并拒绝子类型的实例,AKA 子类)。

通常,在 Python 中,您当然希望您的代码支持继承(由于继承非常方便,因此阻止使用您的代码使用它会很糟糕!),所以 isinstance 比检查 {2 的身份更糟糕}s 因为它无缝地支持继承。

请注意,这并不是说 isinstance ——它只是不如检查类型的相等性。正常的、Pythonic 的首选解决方案几乎总是“鸭子类型”:尝试使用参数 就好像 它是某种所需的类型,在 try/except 语句中捕获所有如果参数实际上不是该类型(或任何其他类型很好地模仿它;-),则可能出现异常,并且在 except 子句中尝试其他内容(使用参数“好像”它是其他类型)。

basestring ,然而,一个非常特殊的情况 - 存在的内置类型允许您使用 isinstancestrunicode 子类 { 1})。字符串是序列(你可以循环它们,索引它们,切片它们,......),但你通常希望将它们视为“标量”类型——处理各种类型的字符串有点不方便(但相当频繁的用例)字符串(可能还有其他标量类型,即不能循环的类型)以一种方式,所有容器(列表、集合、字典等)以另一种方式,basestringisinstance 可以帮助您做到这一点——这个成语的整体结构是这样的:

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

您可以说 basestring 是一个抽象基类(“ABC”)——它不为子类提供具体功能,而是作为“标记”存在,主要用于 isinstance。这个概念在 Python 中显然是一个不断发展的概念,因为引入了它的泛化的 PEP 3119 已被接受并已从 Python 2.6 和 3.0 开始实施。

PEP 明确指出,虽然 ABC 通常可以替代鸭式打字,但这样做通常没有太大的压力(参见 here)。然而,在最近的 Python 版本中实现的 ABC 确实提供了额外的好处:isinstance(和 issubclass)现在不仅仅意味着“派生类的[一个实例]”(特别是,任何类都可以用一个 ABC,以便它将显示为子类,并将其实例显示为 ABC 的实例);并且 ABC 还可以通过模板方法设计模式应用程序以非常自然的方式为实际子类提供额外的便利(请参阅 herehere [[part II]] 了解更多关于 TM DP 的信息,一般来说,特别是在 Python 中,独立于 ABC)。

有关 Python 2.6 中提供的 ABC 支持的基本机制,请参阅 here;对于它们的 3.1 版本,非常相似,请参见 here。在这两个版本中,标准库模块 collections(即 3.1 版本 — 对于非常相似的 2.6 版本,请参阅 here)提供了几个有用的 ABC。

就这个答案而言,保留关于 ABC 的关键(除了 TM DP 功能可以说是更自然的位置,与诸如 UserDict.DictMixin 之类的 mixin 类的经典 Python 替代方案相比)是它们使 isinstance(和issubclass)(在 Python 2.6 及后续版本中)比以前(在 2.5 及之前版本中)更具吸引力和普遍性,因此,相比之下,在最近的 Python 版本中检查类型相等性比现在更糟糕以前是。


'请注意,并不是说 isinstance 好——它只是比检查类型的相等性要好。正常的、Pythonic 的首选解决方案几乎总是“鸭式打字”' 这是一个相当有限的观点:在类型反映语法的解释器中使用 isinstance() 的情况非常好。成为“Pythonic”并不是一切!
基本字符串在 Python 3 中不可用。
@GeneCallahan,因为有很好的案例,并不意味着所说的不是一个好的一般规则。我同意提前检查类型肯定有它的位置,但让鸭子嘎嘎应该更灵活有效地涵盖大多数情况。
@erobertc,根据 What's New in Python 3.0,“删除了内置的 basestring 抽象类型。改用 str 。”
当没有目标时,我永远不会理解形容词 betterworse。如果您不知道为什么,事情怎么能更好?如果您也不想检查子类,isinstance更好。它只是做了一个不同的事情。
b
btalb

这是一个示例,其中 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 也适用于子类。

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


因为在某些情况下您不想要 isInstance 行为我会争辩说没有“更好”。他们只是做一些不同的事情。
-1,因为“isinstance 比 type 更好”是一个误导性的评论。乍一看,它被理解为“不推荐使用 type,请改用 isinstance”。例如,我想要的正是 type() 检查,但由于这个原因,我被误导了一小段时间(并且不得不进行一点调试)。
这是它们工作方式不同的一个很好的例子,但我只是遇到了一个我特别需要 type() 而不是 isinstance() 的情况。一个不是更好;他们是为了不同的事情。
请你告诉我 - 你为什么使用 == 而不是使用“is”?
@variable "如果两个变量指向同一个对象,则返回 True,如果变量引用的对象相等,则 ==。"请参阅this SO post。我不确定它在这个答案的上下文中是否重要。
R
Russia Must Remove Putin

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

类型检查

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

所以,回答这个问题:

Python 中 isinstance() 和 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,我们可以支持 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 可以用来检查多个类,使用 type(obj) in (A, B, C)

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

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

同样,不同之处在于 isinstance 支持可以在不破坏程序的情况下替换父类的子类,这种属性称为 Liskov 替换。

不过,更好的是,反转您的依赖关系并且根本不检查特定类型。

结论

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


如果您在 your_module.py 中检查 isinstance(instance, y) 并使用 from v.w.x import y,然后导入该检查,但是当您实例化 instance 时,您使用 from x import y 而不是在 your_module.py 中导入 y 的方式,isinstance check 会失败,即使它是同一个类。
E
Esparta Palma

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

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

或者,使用 basestring 抽象类:

if isinstance(b, basestring):
    do_something_else()

A
Alec

一个实际的用法差异是它们如何处理 booleans

TrueFalse 只是在 python 中表示 10 的关键字。因此,

isinstance(True, int)

isinstance(False, int)

两者都返回 True。两个布尔值都是整数的实例。然而,type() 更聪明:

type(True) == int

返回 False


G
Grijesh Chauhan

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

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

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


C
Cheney

对于真正的差异,我们可以在 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)})

顺便说一句:最好不要混合使用 relative and absolutely import,使用 project_dir 中的 absolutely import(由 sys.path 添加)


p
panos

type() 和 isinstance() 的区别

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

isinstance() ->返回一个布尔值

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

另一方面,如果您不了解继承链并且需要挑选,请选择 type(x) == ...

type 的另一个有趣案例是当您检查 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