为什么我可以在 Python 中调用抽象类方法?

Jos*_*ilo 2 python

如果我用抽象方法定义一个抽象类:

import abc


class A(abc.ABC):

    @classmethod
    @abc.abstractmethod
    def foo(cls):
        pass
Run Code Online (Sandbox Code Playgroud)

我无法实例化它(如预期):

>>> A()
TypeError: Can't instantiate abstract class A with abstract methods foo
Run Code Online (Sandbox Code Playgroud)

但是我可以毫无错误地调用它的抽象方法。

>> A.foo()
Run Code Online (Sandbox Code Playgroud)

这种行为是否记录在某处?

在 Python 3.6 和 3.7 上测试。

Ser*_*sta 5

没有什么是明确的。

简单的abstractmethod装饰器文档说:

一个具有从 ABCMeta 派生的元类的类不能被实例化,除非它的所有抽象方法和属性都被覆盖。

PEP 3119 说:

包含至少一个使用此装饰器声明的方法的类尚未被覆盖但无法实例化。

然后

实现@abstractmethod装饰器将函数属性__isabstractmethod__设置为值 True。该ABCMeta.__new__方法将 type 属性计算__abstractmethods__为具有__isabstractmethod__值为 true的属性的所有方法名称的集合。它通过组合__abstractmethods__基类的属性,在新类 dict 中添加所有具有 true__isabstractmethod__属性的方法的名称,并删除新类 dict 中没有 true属性的所有方法的名称来实现这一点__isabstractmethod__。如果结果__abstractmethods__集非空,则该类被认为是抽象的,并且尝试实例化它会引发TypeError

我对实现部分的解释是,@abstractmethod永远不会阻止调用该方法,而只是说该类无法实例化,并且子类仍然是抽象的,除非它覆盖其所有抽象方法。

所以我不会说这是设计使然,但它至少是一个假设的副作用。