试图创建一个既是Python抽象类又继承PySide6类时出现元类冲突。

7

我试图创建一个既是抽象基类又继承了一个任意的 PySide6 类的类。然而,下面的代码会产生错误:TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

from abc import ABC, abstractmethod

from PySide6.QtWidgets import QApplication, QWidget


class MyBaseWidget(QWidget, ABC):

    def __init__(self, parent=None):
        super().__init__(parent=parent)
    
    @abstractmethod
    def foo(self):
        pass


class MyConcreteWidget(MyBaseWidget):

    def __init__(self, parent=None):
        super().__init__(parent=parent)


app = QApplication([])
widget = MyConcreteWidget()
widget.show()
app.exec_()

我尝试使用以下解决方案来解决这个问题(灵感来自解决元类冲突http://www.phyast.pitt.edu/~micheles/python/metatype.html多重继承元类冲突等)。

class MyMeta(ABCMeta, type(QWidget)): pass


class MyBaseWidget(QWidget, metaclass=MyMeta):

    def __init__(self, parent=None):
        super().__init__(parent=parent)
    
    @abstractmethod
    def foo(self):
        pass


class MyConcreteWidget(MyBaseWidget):

    def __init__(self, parent=None):
        super().__init__(parent=parent)


app = QApplication([])
widget = MyConcreteWidget()
widget.show()
app.exec_()

这段代码没有出现错误,但是我本来期望会出现一个错误,像这样的 TypeError: Can't instantiate abstract class MyConcreteWidget with abstract methods foo 当实例化 MyConcreteWidget 时。不能强制执行基类接口真的削弱了抽象基类的好处。有什么解决办法吗?


如果可以的话,为什么您需要一个QWidget的元类?只有少数情况建议这样做,并且在其中大多数情况下我意识到通常不值得,因为它会使事情变得复杂,并且容易出现难以追踪和解决的问题。 - musicamante
@musicamante 的主要目标是创建一个定制的抽象 QWidget 类(QWidget 是任意的...它可以是任何 Qt 类),以便继承它的其他类必须实现该抽象方法(或方法)。这个问题不一定需要使用元类,但是 ABCMetaQWidget 的元类冲突,所以我最初的想法是需要解决那个元类冲突。 - physhics
如果你实际上不需要元类,那么你可以直接从一个基本的Python对象继承,该对象实现了你所需的方法吗? - musicamante
所有具体的小部件都需要以自己的方式实现 foo,这就是为什么在 MyBaseWidget 中它是抽象的;没有 foo 的默认实现。元类冲突是我尝试实现的副作用,因为 Python 的 ABC 类与 Qt 类不兼容。 - physhics
1个回答

4

以下解决方案对我来说能够得到所需的结果。

首先获取您想要扩展的Classes和它们的Metaclasses

from abc import ABC, ABCMeta
from PySide6.QtCore import QObject

QObjectMeta = type(QObject)

然后根据你想要的两个元类创建你的CustomMetaClass

class _ABCQObjectMeta(QObjectMeta, ABCMeta):...

最后,通过继承这两个类并将元类设置为“CustomMetaclass”,创建一个名为“InterfaceClass”的类。
class ABCQObject(QObject, ABC, metaclass=_ABCQObjectMeta):...

这个过程可以应用于您想要的任何类。

最终代码:

from abc import ABC, ABCMeta

from PySide6.QtCore import QObject
from PySide6.QtWidgets import QWidget

QObjectMeta = type(QObject)
QWidgetMeta = type(QWidget)

class _ABCQObjectMeta(QObjectMeta, ABCMeta):...
class _ABCQWidgetMeta(QObjectMeta, ABCMeta):...


class ABCQObject(QObject, ABC, metaclass=_ABCQObjectMeta):...
class ABCQWidget(QWidget, ABC, metaclass=_ABCQWidgetMeta):...

现在你可以像继承ABC一样继承这个Abstract类。例如:

from abc import abstractmethod
import ABCQWidget


class BaseView(ABCQWidget):

    @abstractmethod
    def setupManager(self, manager):...

    @abstractmethod
    def updateContent(self, content):...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接