首先来看下面一段代码:
from collections import abc
class MyClass:
def __contains__(self, item):
return item in [1, 2, 3]
print(isinstance(MyClass(), abc.Container)) # True
这里MyClass并没有显示继承abc.Container类型,为何最后输出了True呢?
一. isinstance 的作用
isinstance 本身并不会检查对象是否实现了特定的方法。它的主要作用是检查对象是否是某个类或其子类的实例。具体来说,isinstance(obj, cls) 会检查 obj 是否是 cls 类型或其子类的实例。因此,isinstance 只关注类的继承关系,而不会关心类的具体方法实现。
isinstance(obj, SomeClass) # 检查 obj 是否是 SomeClass 或其子类的实例
二. abc.Collection 和隐式接口检查
abc.Collection 和其他抽象基类(如 abc.Iterable,abc.Mapping 等)不是通过继承关系直接强制类实现某些方法,而是通过 协议(protocol) 来定义接口。具体来说,abc.Collection 本身会通过__subclasshook__方法来自动检查类是否实现了必要的魔法方法(例如__contains__() 和__len__())。
当你使用 isinstance(obj, Collection) 时,Collection 类型会通过__subclasshook__ 方法检查 obj 类是否实现了__contains__() 和__len__() 方法。如果 obj 的类实现了这些方法,isinstance 会返回 True,即认为 obj 是 Collection 类型的实例。这个检查机制由 abc.Collection 通过__subclasshook__实现。
三. 隐式继承关系
这个“隐式继承”并不是传统意义上的继承。在 Python 中,抽象基类(如 abc.Collection)不强制类继承它们。相反,抽象基类通过协议(方法签名和行为)来定义要求,具体类只需要实现协议中定义的方法即可。Python 会通过__subclasshook__方法来检查类是否符合这些协议,而 isinstance 调用会利用这些检查。
换句话说,abc.Collection 等抽象基类通过__subclasshook__机制自动检查类是否实现了符合接口要求的方法,而不是通过传统的类继承关系。这是 Python 中的“鸭子类型”特性的一部分——只要一个类看起来像某个类型(即它实现了该类型要求的方法),就可以被认为是该类型的实例。
四.__subclasshook__和方法检查
每个 abc 模块中的抽象基类(如 abc.Collection)都有一个__subclasshook__方法。这个方法会在 isinstance() 被调用时触发,并对目标类进行检查。以 abc.Collection 为例,当你执行 isinstance(obj, Collection) 时,Collection 的__subclasshook__方法会检查 obj 是否实现了__contains__() 和__len__() 方法。
__subclasshook__的实现可以是这样的:
from collections.abc import Collection
class MyCollection:
def __contains__(self, item):
return item in [1, 2, 3]
def __len__(self):
return 3
此时 MyCollection 没有显式继承 Collection,但仍然会通过__subclasshook__被认为是 Collection 的子类
print(isinstance(MyCollection(), Collection)) # True
Collection 内部的__subclasshook__方法会检查 MyCollection 是否实现了__contains__() 和__len__() 方法,而不是通过传统的类继承关系来判断。因此,即使 MyCollection 没有显式继承 Collection,只要它实现了这些方法,isinstance 仍然会返回 True。
五、总结
isinstance 只是检查对象是否是某个类或其子类的实例,它并不关心类的方法实现。
abc.Collection 等抽象基类通过__subclasshook__方法来隐式检查一个类是否实现了符合接口要求的方法(如__contains__() 和__len__())。
这种方法检查由抽象基类(例如 abc.Collection)实现,而不是 isinstance 自身。isinstance 会利用这些检查来判断一个对象是否符合某个类型的要求。
因此,隐式继承关系和方法检查是由 abc.Collection 类(以及其他抽象基类)内部的机制__subclasshook__来完成的,而不是由 isinstance 直接实现的。
基础扩展(以下粗体字均为前后双下划线的方法,由于编辑功能原因显示为加粗)
类似的collections.abc中还有很多类都实现了__subclasshock__方法,比如abc.Sized(实现 len())、abc.Mapping(实现 getitem(), iter(), 和__len__() 方法)、abc.MutableMapping(实现 setitem(), delitem(), 以及 getitem(), iter(), 和 len() 方法)、abc.Sequence(实现 getitem(), len() 方法,并可以选择性地实现 contains() 和 index() 方法)、abc.MutableSequence(实现 setitem(), delitem(), getitem(), len() 方法)、abc.Set(实现 contains() 和 iter() 方法)、abc.MutableSet(实现 add(), __remove(), contains(), 和 iter() 方法)

被折叠的 条评论
为什么被折叠?



