从两个元类派生时 __init__ 中的类型错误

Type error in __init__ when deriving from two metaclasses

我想制作派生自 PyQt5 QtWidget.QWidgetabc.ABCMeta 的 class。这两个 classes 都有自己的元 class 作为类型,因此,根据 this page and ,我需要创建自己的元 class,该元 class 派生自元 [=32= QWidgetabc.ABCMeta 的 ]es,并明确将其用作我的 class.

的元 class

到目前为止一切顺利,我已经定义了一个 QtAbcMeta class 并将其用作我的 ConcreteWidget class 的 metaclass(见下文) .

import abc
from PyQt5 import QtWidgets, QtCore


class AbstractClass(metaclass=abc.ABCMeta):

    def __init__(self, name):
        self._name = name

    @abc.abstractmethod
    def myMethod():
        pass


class QtAbcMeta(type(QtWidgets.QWidget), type(AbstractClass)):
    pass


class ConcreteWidget(QtWidgets.QWidget, AbstractClass, metaclass=QtAbcMeta):

    def __init__(self, name, parent=None):
        AbstractClass.__init__(self, name)
        QtWidgets.QWidget.__init__(self, parent=parent)  # This gives a type error.


    def myMethod():
        print("My widget does something")


def main():
    app = QtWidgets.QApplication([])
    myWidget = ConcreteWidget('my name', parent=None)

if __name__ == "__main__":
    main()

但是,当我尝试调用 QtWidgets.QWidget 方法的 __init__ 方法来设置父级时,我得到以下类型错误:

Traceback (most recent call last):
  File "main.py", line 36, in <module>
    main()
  File "main.py", line 33, in main
    myWidget = ConcreteWidget('my name', parent=None)
  File "main.py", line 24, in __init__
    QtWidgets.QWidget.__init__(self, parent=parent)  # This gives a type error.
TypeError: __init__() missing 1 required positional argument: 'name'

我不知道这里出了什么问题。 QtWidgets.QWidget.__init__ 的签名是否以某种方式改变了?任何帮助将不胜感激。

QT classes 旨在以合作方式在现代 Python 代码中使用 - 这意味着它们在内部使用 Python 的 super() , 以确保所有 superclasses 中的所有正确方法都使用各自的参数调用。

super() 的创建恰恰是为了避免使用 super-classes __init__(和其他重写方法)硬编码调用class 个名字,这样你就不用担心调用顺序了。

唯一的问题是每个 class 打算用作 multi-class mixin 必须 "know" 怎么样,提取它使用的命名参数,并使用剩余的参数再次调用 super。 QT 代码更进一步,检查其他 classes 的所有命名参数是否都已呈现给它,否则会出错。

不仅如此,由于 Qt classes 本身使用 super,这意味着您的 __init__ 抽象 class 被调用了两次。它不会对这个简单的代码产生影响,但在更复杂的基础 classes 中可能会出现问题。

所以,只需重写您的 __init__ 方法,以 "pythonic" 方式完成:

class ConcreteWidget(QtWidgets.QWidget, AbstractClass, metaclass=QtAbcMeta):

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