如何正确地从abc接口和另一个类继承并保留限制以创建缺少实现的对象?

0 投票
1 回答
30 浏览
提问于 2025-04-13 13:49

我正在尝试把一个实现了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 个回答

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 模块的异常。

撰写回答