如何正确地从abc接口和另一个类继承并保留限制以创建缺少实现的对象?
我正在尝试把一个实现了abc
接口的类和另一个类结合在一起。
我们先来看一个简单的abc
示例:
import abc
class Interface(abc.ABC):
@abc.abstractmethod
def pure_virtual_func(self):
raise NotImplementedError
class Impl(Interface):
def __init__(self):
pass
impl = Impl()
当创建Impl
的时候,这段代码会失败,错误信息是:无法实例化抽象类Impl,因为它有抽象方法pure_virtual_func
。这很好,这正是你所期待的。
现在,当Impl
需要从另一个类继承时:
import abc
from PySide6.QtWidgets import QApplication, QWidget
class Interface(abc.ABC):
@abc.abstractmethod
def pure_virtual_func(self):
raise NotImplementedError
class Impl(QWidget,Interface):
def __init__(self):
pass
app = QApplication()
impl = Impl()
你会遇到错误:错误:元类冲突:派生类的元类必须是所有基类元类的(非严格)子类
。
根据一些帖子(比如解决元类冲突和抽象类继承自ABC和QMainWindow),推荐这样做:
import abc
from PySide6.QtWidgets import QApplication, QWidget
class Interface(abc.ABC):
@abc.abstractmethod
def pure_virtual_func(self):
raise NotImplementedError
class Meta(type(QWidget), type(Interface)):
pass
class Impl(QWidget, Interface, metaclass=Meta):
def __init__(self):
pass
app = QApplication()
impl = Impl()
好的,现在metaclass
的错误消失了。但是你也不再收到无法实例化抽象类Impl,因为它有抽象方法pure_virtual_func
的错误了,现在impl
被简单地创建了,如果调用pure_virtual_func
,你会得到NotImplementedError
异常。
这样一来,abc
检测未实现的纯虚方法的好功能就消失了,怎么才能从Interface
和另一个类(在我的例子中是QWidget
)继承,并保留未实现的纯虚方法检测呢?
有很多帖子在解释如何处理元类的相关问题,但我没有找到任何一个能保留abc
检测未实现纯虚方法能力的解决方案。
1 个回答
简短描述
你看到的这个行为是因为你新创建的元类(Meta Class)绕过了 ABCMeta
这个元类对任何 abc
抽象类的检查。这和 QWidget
的元类 QMetaObject
是不一样的。
建议
与其使用继承,不如尝试通过组合来重新设计你的代码,这样可以避免使用这种方法。Python 允许一个类有多个父类,但如果不小心就会出现 diamond problem
(菱形问题)。不过,如果你因为某些 限制 还是想实现你想要的行为,可以尝试以下方法。
代码
import abc
from PySide6.QtWidgets import QApplication, QWidget
import inspect
class Interface(abc.ABC):
@abc.abstractmethod
def pure_virtual_func(self):
raise NotImplementedError
class Meta(type(Interface),type(QWidget)):
pass
class Impl(Interface, QWidget, metaclass=Meta):
def __init__(self):
self._check_abstract_methods()
def _check_abstract_methods(self):
for name, value in inspect.getmembers(type(self), predicate=inspect.isfunction):
if getattr(value, "__isabstractmethod__", False):
raise NotImplementedError(f"The abstract method '{name}' is not implemented in '{type(self).__name__}'.")
app = QApplication()
new_impl = Impl()
我们使用 inspect 模块,明确检查类的所有成员是否是抽象方法。如果是 True
,我们就抛出一个类似于 abc
模块的异常。