为何int.__mro__不包含numbers.Integral?与isinstance认知冲突的疑问
为什么
isinstance(1, numbers.Integral)返回True,但numbers.Integral不在int.__mro__里? 嘿,这个问题问到点子上了!我刚接触Python抽象基类(ABC)的时候也被这个“矛盾”困惑过,其实核心原因是Python的抽象基类支持虚拟子类注册机制,这打破了我们对isinstance常规逻辑的认知。
先理清常规的isinstance逻辑
通常来说,isinstance(obj, cls)确实会检查obj所属类的MRO(方法解析顺序)元组中是否包含cls,或者cls是该类的某个直接/间接基类。比如:
print(isinstance(1, int)) # True,int在int.__mro__里 print(isinstance(1, object)) # True,object在int.__mro__的末尾 print(object in int.__mro__) # True
这部分和你最初的认知是完全一致的。
抽象基类的“虚拟子类”机制是关键
numbers.Integral是一个抽象基类(ABC),Python的ABC体系允许通过注册的方式,让一个类成为ABC的“虚拟子类”——即使这个类没有显式继承该ABC。
具体来说,int类被注册成了numbers.Integral的虚拟子类,这个注册操作在numbers模块的源码里是这样实现的(简化版):
from abc import ABCMeta class Integral(metaclass=ABCMeta): # ... 抽象方法定义 ... Integral.register(int) # 将int注册为Integral的虚拟子类
虚拟子类对isinstance的影响
ABC的元类ABCMeta重写了__instancecheck__和__subclasscheck__方法,当你调用isinstance(obj, ABC)时,它会做两件事:
- 先检查常规的MRO继承关系;
- 如果没找到,再检查该类是否被注册为这个ABC的虚拟子类。
所以即使numbers.Integral不在int.__mro__里,只要int被注册过,isinstance(1, numbers.Integral)就会返回True。我们可以用代码验证这一点:
import numbers print(isinstance(1, numbers.Integral)) # 输出: True print(numbers.Integral in int.__mro__) # 输出: False print(int in numbers.Integral.__subclasses__()) # 输出: True,能看到注册的虚拟子类
总结一下
isinstance的判断逻辑并不只依赖MRO,当涉及抽象基类时,还会考虑虚拟子类注册的情况。这是Python为了支持“鸭子类型”和抽象接口定义而设计的灵活机制,让不同的类可以统一被识别为某个抽象类型,而不需要显式继承。
内容的提问来源于stack exchange,提问作者Timur
相关产品推荐
相关产品推荐

