代码之家  ›  专栏  ›  技术社区  ›  titusjan

从两个元类派生时,在初始化中输入错误

  •  0
  • titusjan  · 技术社区  · 7 年前

    我想创建一个从pyqt5派生的类 QtWidget.QWidget 和一个 abc.ABCMeta . 根据 this page this SO question ,我需要创建自己的从 QWidget 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__ 方法 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'
    

    我不知道这里出了什么事。具有以下签名: QtWidgets.QWidget.__init__ 有什么变化吗?任何帮助都将不胜感激。

    2 回复  |  直到 7 年前
        1
  •  1
  •   jsbueno    7 年前

    Qt类被设计成以合作的方式在现代Python代码中使用——这意味着它们在内部使用了Python的 super() ,以确保调用所有超类中的所有正确方法及其各自的参数。

    创造 super() 完全是为了避免对超级类进行硬代码调用 __init__ (和其他重写方法)使用超类名,这样就不必担心调用顺序。

    唯一的一点是,每个打算用作多类混合的类都必须“知道”它是如何使用的,提取它使用的命名参数,然后调用 super 用剩下的参数。 qt代码更进一步,检查是否向它提供了其他类的所有命名参数,否则它会出错。

    更重要的是,由于qt类本身使用super,这意味着 _初始化__ 在抽象类中被调用两次。在这个简单的代码中,它不会有什么不同,但在更复杂的基类中,它可能是一个问题。

    所以,只要重写你的 _初始化__ 以“蟒蛇”的方式进行的方法:

    class ConcreteWidget(QtWidgets.QWidget, AbstractClass, metaclass=QtAbcMeta):
    
        def __init__(self, name, parent=None):
            super().__init__(name=name, parent=parent)
    
        2
  •  1
  •   eyllanesc    7 年前

    根据 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)