使用类方法实现抽象类不会引发异常

时间:2019-02-06 17:10:58

标签: python python-3.x

我正在尝试将一种方法既实现为抽象方法又实现为类方法,但是这样做并不会带来抽象类的任何好处。

例如:

from abc import ABC, abstractmethod

class BasePipeline(ABC):

    @classmethod
    @abstractmethod
    def consume_frame(cls):
        pass

    @abstractmethod
    def consume_frame_two(self):
        pass

class AnotherSubclass(BasePipeline):

    @classmethod
    def does_nothing(cls):
        a = 1 + 1

# Call it. 
AnotherSubclass.consume_frame()

这不会引发任何异常,也不会出错。我希望它能像consume_frame_two is not implementedconsume_frame is not implemented这样说。

不知道预期的行为是什么,或者我是否做错了什么。我希望AnotherSubclass.consume_frame()引发一个异常,如果它不能作为类方法正确实现。

1 个答案:

答案 0 :(得分:1)

您的代码不会尝试创建AnotherSubclass类的实例。它所做的只是访问标记为抽象的classmethod的实现。 Python的ABC抽象类并非旨在阻止这种访问。

abc模块旨在帮助您定义 protocol interface ,这是一个基类,用于设置关于在混凝土上必须存在哪些属性的期望应该被视为相同的对象。

为此,您可以使用ABC子类做的所有事情是防止创建具有至少一个abstractmethodabstractproperty属性的类层次结构中任何类的实例。来自@abc.abstractmethod() documentation

  

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

任何abstractmethod装饰的方法都可以仍然被调用;没有防止这种情况发生的机制,实际上,模块的特定目标是具体实现可以使用super().name()访问abstractmethod对象的实现。来自同一来源:

  

可以使用任何常规的“超级”调用机制来调用抽象方法

  

注意:与Java抽象方法不同,这些抽象方法可能具有实现。可以通过super()机制从覆盖它的类中调用此实现。这在使用协作式多重继承的框架中作为超级调用的端点很有用。

该类的任何其他属性都可以与其他类(包括classmethod对象)相同地使用。

在幕后,每个ABCMeta元类都为您创建的每个类提供了一个__abstractmethods__属性,该属性是一个frozenset对象,具有该类中任何属性的名称__isabstractmethod__属性设置为True,子类仅需使用与父抽象方法对象相同的名称,将其设置为未将__isabstractmethod__设置为true的属性即可删除该类的集合中的名称。然后,当您尝试创建__abstractmethods__不为空的类的实例时,Python将引发异常。

如果需要进一步锁定类定义,则必须提出我们自己的元类或其他机制来实现这些规则。例如,您可以将classobject属性包装在自己的descriptor object中,以防止调用绑定到具有非空__abstractmethods__属性的类的类方法。