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 子类的字典(我们应该能够,如果我们希望我们的代码遵循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 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 进行类型检查 - 除非您真的需要知道实例的确切类。