我正在尝试将一种方法既实现为抽象方法又实现为类方法,但是这样做并不会带来抽象类的任何好处。
例如:
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 implemented
和consume_frame is not implemented
这样说。
不知道预期的行为是什么,或者我是否做错了什么。我希望AnotherSubclass.consume_frame()
引发一个异常,如果它不能作为类方法正确实现。
答案 0 :(得分:1)
您的代码不会尝试创建AnotherSubclass
类的实例。它所做的只是访问标记为抽象的classmethod
的实现。 Python的ABC抽象类并非旨在阻止这种访问。
abc
模块旨在帮助您定义 protocol 或 interface ,这是一个基类,用于设置关于在混凝土上必须存在哪些属性的期望应该被视为相同的对象。
为此,您可以使用ABC
子类做的所有事情是防止创建具有至少一个abstractmethod
或abstractproperty
属性的类层次结构中任何类的实例。来自@abc.abstractmethod()
documentation:
具有从
ABCMeta
派生的元类的类,除非其所有抽象方法和属性都被覆盖,否则无法实例化。
任何abstractmethod
装饰的方法都可以仍然被调用;没有防止这种情况发生的机制,实际上,模块的特定目标是具体实现可以使用super().name()
访问abstractmethod
对象的实现。来自同一来源:
可以使用任何常规的“超级”调用机制来调用抽象方法
和
注意:与Java抽象方法不同,这些抽象方法可能具有实现。可以通过
super()
机制从覆盖它的类中调用此实现。这在使用协作式多重继承的框架中作为超级调用的端点很有用。
该类的任何其他属性都可以与其他类(包括classmethod
对象)相同地使用。
在幕后,每个ABCMeta
元类都为您创建的每个类提供了一个__abstractmethods__
属性,该属性是一个frozenset
对象,具有该类中任何属性的名称__isabstractmethod__
属性设置为True
,子类仅需使用与父抽象方法对象相同的名称,将其设置为未将__isabstractmethod__
设置为true的属性即可删除该类的集合中的名称。然后,当您尝试创建__abstractmethods__
不为空的类的实例时,Python将引发异常。
如果需要进一步锁定类定义,则必须提出我们自己的元类或其他机制来实现这些规则。例如,您可以将classobject
属性包装在自己的descriptor object中,以防止调用绑定到具有非空__abstractmethods__
属性的类的类方法。