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进行类型检查-除非您确实需要知道实例的精确类。