从两个元类派生时,__ init__中的类型错误

时间:2018-10-22 14:54:29

标签: python pyqt pyqt5 metaclass

我想创建一个派生自PyQt5 QtWidget.QWidgetabc.ABCMeta的类。这两个类都有其自己的元类作为类型,因此,根据this pagethis SO question,我需要创建自己的元类,该元类派生自QWidget和{{1 }},并明确地将其用作我的课程的元类。

到目前为止,我已经定义了一个abc.ABCMeta类,并将其用作我的QtAbcMeta类的metaclass(请参见下文)。

ConcreteWidget

但是,当我尝试调用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() 方法的__init__方法来设置父对象时,会收到以下TypeError:

QtWidgets.QWidget

我不知道这是怎么了。 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' 的签名是否有所更改?任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

根据the docs,您必须将所有参数传递给QWidget,尽管您不需要它:

class ConcreteWidget(QtWidgets.QWidget, AbstractClass, metaclass=QtAbcMeta):
    def __init__(self, name, parent=None):
        AbstractClass.__init__(self, name)
        QtWidgets.QWidget.__init__(self, name=name, parent=parent)

答案 1 :(得分:1)

QT类旨在以协作方式在现代Python代码中使用-这意味着它们在内部使用Python的super(),以确保使用其各自的参数调用所有超类中的所有适当方法。

super()的创建完全是为了避免使用超级类名称对超级类__init__(和其他替代方法)进行硬编码的调用,因此您不必担心呼叫顺序。

唯一的是,每个打算用作多类混合的类都必须“了解”它的状态,提取其使用的命名参数,然后使用其余参数再次调用super 。 QT代码更进一步,并检查是否为其他类提供了所有命名的参数,否则会出错。

更重要的是,由于Qt类本身使用了super,这意味着您在抽象类中的__init__被调用了两次。在这个简单的代码中不会有什么不同,但是在更复杂的基类中可能是个问题。

因此,只需重写您的__init__方法即可以“ pythonic”方式进行操作:

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

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