为什么要在Python中调用抽象类方法?

时间:2018-08-13 09:06:02

标签: python

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

import abc


class A(abc.ABC):

    @classmethod
    @abc.abstractmethod
    def foo(cls):
        pass

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

>>> A()
TypeError: Can't instantiate abstract class A with abstract methods foo

但是我可以正确地调用它的抽象方法。

>> A.foo()

此行为记录在某处吗?

在Python 3.6和3.7上进行了测试。

3 个答案:

答案 0 :(得分:2)

fooclassmethod,并且property可以直接由类本身调用类方法。
通过

In [3]: A.foo()  

您不是要实例化类A,而是要在类foo上调用函数A

答案 1 :(得分:2)

没有什么是明确的。

abstractmethod装饰器的文档说:

  

具有从ABCMeta派生的元类的类,除非其所有抽象方法和属性都被覆盖,否则无法实例化。

PEP 3119说:

  

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

及以后

  

实现@abstractmethod装饰器将函数属性__isabstractmethod__设置为True。 ABCMeta.__new__方法将类型属性__abstractmethods__计算为所有具有__isabstractmethod__属性且其值为true的方法名称的集合。它通过组合基类的__abstractmethods__属性,在新类dict中添加具有真实__isabstractmethod__属性的所有方法的名称,以及删除新类中所有方法的名称来实现此目的没有真正的__isabstractmethod__属性的字典。如果生成的__abstractmethods__集为非空,则该类被视为抽象类,尝试实例化该类将引发TypeError

我对实现部分的解释是@abstractmethod从不阻止调用该方法,而只是说无法实例化该类,并且除非覆盖了所有抽象方法,否则子类仍将是抽象的。 / p>

所以我不会说这是设计,但至少是一种假定的副作用。

答案 2 :(得分:1)

子类abc.ABC的子类表示类A不能直接实例化。

在类型/名称解析期间,@abc.abstractmethod装饰器会强制检查A的任何子类。如果class subofA(A):没有实现修饰的方法,则会引发异常。

一旦通过类型/名称解析,则abstractmethod装饰器不会阻止您调用该方法。毕竟,除非没有实例,否则无法调用该方法。

通过用开发者foo@classmethod装饰@abstractmethod,您可以指定A.foo()可以安全地调用而无需实例化类,但是子类{ {1}}必须实现一种重写方法来保留该行为。