乘以继承自 QWidget 和另一个基类?

Posted

技术标签:

【中文标题】乘以继承自 QWidget 和另一个基类?【英文标题】:Multiply inherit from QWidget and another base class? 【发布时间】:2018-10-10 17:06:26 【问题描述】:

我正在尝试创建一个PyQt5.QtWidgets.QWidget 派生小部件,同时从另一个基类Base 继承。

Base 继承会导致调用QWidget 构造函数时出错,说我从未提供Base 需要的参数。

这就是我尝试调用QWidgetBase 构造函数的方式:

class Deriv(QtWidgets.QWidget, Base):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        Base.__init__(self, "hello world")

我得到的错误是:

    QtWidgets.QWidget.__init__(self)
TypeError: __init__() missing 1 required positional argument: 'id'

是否可以同时继承QWidgetBase,如果可以,如何正确调用它们各自的构造函数?

这是一个示例应用程序,它重现了我遇到的错误:

#!/usr/bin/env python3
import sys
from PyQt5 import QtWidgets

class Base(object):
    def __init__(self, id):
        self.id = id

class Deriv(QtWidgets.QWidget, Base):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        Base.__init__(self, "hello world")

        self.show()

def main():
    app = QtWidgets.QApplication(sys.argv)
    d = Deriv()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

这是回溯:

Traceback (most recent call last):
  File "./test.py", line 22, in <module>
    main()
  File "./test.py", line 18, in main
    d = Deriv()
  File "./test.py", line 11, in __init__
    QtWidgets.QWidget.__init__(self)
TypeError: __init__() missing 1 required positional argument: 'id'

请注意,如果我仅继承自 QWidget(所以只需删除所有引用 Base 的内容),那么代码就可以工作

class Deriv(QtWidgets.QWidget):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)

        self.show()

【问题讨论】:

错误信息非常明确;您需要将self.id 作为参数传递给QtWidgets.QWidget.__init__ QWidget 不接受 id 参数。这是错误:TypeError: QWidget(parent: QWidget = None, flags: Union[Qt.WindowFlags, Qt.WindowType] = Qt.WindowFlags()): argument 1 has unexpected type 'str' @chepner 我已经更新了问题以表明不向QWidget 传递任何内容都有效,但只有当我不从其他任何东西继承时 QTWidgets.QWidget 显然使用了super,所以如果你有额外的基类,那么它们的__init__ 方法会被from QTWidgest.QWidget.__init__ 调用,即使你没有' t 首先调用super。 (一旦我找到QTWidgets 的源代码,我就可以发布一个答案。) @MartijnPieters QtWidgets.QWidget 确实有一个父母,但它默认为 None - 为了简洁起见,我已将其删除 - 将其重新添加并没有区别 afaics 【参考方案1】:

我假设QtWidgets.QWidget.__init__ 本身使用super 来调用__init__。对于您的单继承案例,MRO 由三个类组成:[Deriv, QtWidgets.QWidget, object]。调用super(QtWidgets.QWidget, self).__init__ 将调用object.__init__,它不需要任何额外的参数。

在您的多重继承示例中,MRO 看起来像

[Deriv, QtWidgets.QWidget, Base, object]

这意味着现在调用super(QtWidgets.QWidget, self).__init__ 不是指object.__init__,而是Base.__init__,这确实需要一个额外的参数,导致你看到的错误.

【讨论】:

正如我在另一个问题中的一个答案中所建议的那样,我尝试使用QtWidgets.QWidget.__init__(self) 而不是使用super,但这似乎也不起作用 不,它没有,因为即使 没有打电话给superQtWidgets.QWidget.__init__ 确实(或者至少,我假设是这样,基于观察到的行为)。 super 的规则是 每个 类都必须使用它,否则它们都不能。 在文档中确认:pyqt.sourceforge.net/Docs/PyQt5/… 该规则的推论是您需要将您对__init__ 的调用收到的每个 参数传递给超级调用,因为您不知道哪些是被调用链更进一步的预期。 (推论的例外是,如果您是特定方法的“根”类,那么您可以省略特定于继承树“分支”的参数。但是, object 始终是 __init__ 的根,所以你所能做的就是容忍意外的参数并将它们传递出去。)

以上是关于乘以继承自 QWidget 和另一个基类?的主要内容,如果未能解决你的问题,请参考以下文章

QT之对话框

QWidget,QMainWindow,QDialog和QFrame的区别

创建两组具有不同继承的类

QWidget 继承自自定义 QWidget

漫谈QWidget及其派生类(三)

QT学习_常用类及信号和槽