You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何实现所有抽象方法后,isinstance(Test(), MyAbstractClass)仍返回False?

问题:为何collections.abc.Sized无需注册就能通过isinstance检查,自定义抽象类却不行?

某书籍提到,若定义类时实现了抽象类的所有抽象方法,即便未继承该抽象类,isinstance()检查也会返回True。本地测试abc.Sized时符合预期:

from collections import abc

class Test:
    def __len__(self):
        return 0

print(isinstance(Test(), abc.Sized))  # 输出True

但自定义抽象类时却失败了:

from abc import abstractmethod, ABCMeta

class MyAbstractClass(metaclass=ABCMeta):
    @abstractmethod
    def get_size(self):pass

class Test:
    def get_size(self):
        return 0

print(isinstance(Test(), MyAbstractClass))  # 输出False

必须执行MyAbstractClass.register(Test)才能让isinstance返回True。这是为什么?


解答

这是因为collections.abc模块中的抽象基类(比如Sized)内置了结构子类型检测逻辑,而自定义的ABCMeta抽象类默认没有这个功能。

具体来说,abc.Sized的元类实现了__subclasshook__方法——这个特殊方法会在isinstance检查时自动触发,它的作用是判断目标类是否满足抽象基类的“结构要求”:只要类实现了Sized规定的所有抽象方法(这里就是__len__),不管有没有显式继承或注册,isinstance都会返回True。

而你用ABCMeta自定义的MyAbstractClass,默认并没有实现__subclasshook__。此时Python会采用严格的“名义子类型”检查:只有当类显式继承了该抽象类,或者通过register方法完成了显式注册,才会被isinstance判定为抽象类的实例。

如果想让自定义抽象类也支持这种“鸭子类型”的自动检测,你可以给它添加__subclasshook__方法,示例如下:

from abc import abstractmethod, ABCMeta

class MyAbstractClass(metaclass=ABCMeta):
    @abstractmethod
    def get_size(self):
        pass

    @classmethod
    def __subclasshook__(cls, subclass):
        # 检查子类是否实现了get_size方法
        if cls is MyAbstractClass:
            # 遍历方法解析顺序,确认存在get_size属性
            if any("get_size" in B.__dict__ for B in subclass.__mro__):
                return True
        return NotImplemented

添加这个方法后,再运行测试代码,isinstance(Test(), MyAbstractClass)就会返回True了。


内容的提问来源于stack exchange,提问作者Jared Zhu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 22:47:20