1

我最近被问到 pyqt 继承中的一个问题,问题是:假设我有一个带有方法的类 AcloseEvent(event)和一个继承 A 和 QMainWindow 的类 B(因此有一个closeEvent(event)方法)。解决顺序是closeEvent什么?考虑到 python 文档,这将取决于继承顺序。但是下面的例子表明情况并非如此......有人可以帮忙吗?我在带有 PyQt5 的 Windows 上使用 Python3.6.2。

from PyQt5.QtWidgets import QApplication, QMainWindow
import sys

class A():
    def closeEvent(self,event):
        print("A")

class B(QMainWindow):
    def closeEvent(self,event):
        print("B")
        super().closeEvent(event)

class C(A,B):
    pass

class D(B,A):
    pass

class E(QMainWindow,A):
    pass

class F(A,QMainWindow):
    pass

def test(TestClass, msg):
    """Create class instance and show it. Click on cross to close."""
    print(msg)
    app = QApplication(sys.argv)
    test = TestClass()
    test.show()
    app.exec()

test(C,"C(A,B)?") #           >>> A
test(D,"D(B,A)?") #           >>> B
test(E,"E(QMainWindow,A)?") # >>> A ??? Why ???
test(F,"F(A,QMainWindow)?") # >>> A
4

1 回答 1

0

这是一个非常复杂的问题,涉及到 Python 和 C++ 在协作多继承如何工作方面的差异。因此,我将在这里给出的答案更多是简要概述。我认为对于单一的 SO 答案,全面处理可能是不可行的。

部分问题在于 PyQt 如何确定它应该从哪个类继承。这可以通过比较__base__纯 Python 和 PyQt 版本的类层次结构的属性来说明:

class A: pass
class B(QMainWindow): pass
class C(A, B): pass
class D(B, A): pass
class E(QMainWindow, A): pass
class F(A, QMainWindow): pass

print('pyqt:')
print('C:', C.__base__)
print('D:', D.__base__)
print('E:', E.__base__)
print('F:', F.__base__)

class M: pass
class A: pass
class B(M): pass
class C(A, B): pass
class D(B, A): pass
class E(M, A): pass
class F(A, M): pass

print('python:')
print('C:', C.__base__)
print('D:', D.__base__)
print('E:', E.__base__)
print('F:', F.__base__)

输出:

pyqt:
C: <class '__main__.B'>
D: <class '__main__.B'>
E: <class 'PyQt5.QtWidgets.QMainWindow'>
F: <class 'PyQt5.QtWidgets.QMainWindow'>
python:
C: <class '__main__.A'>
D: <class '__main__.B'>
E: <class '__main__.M'>
F: <class '__main__.A'>

这不是错误。这里的差异完全是由于实现细节,我不打算解释(即使我可以)。PyQt 很可能更改其实现以更接近 Python 行为。但它反而选择了妥协,而不是远离 Qt/C++ 中的工作方式。我猜这个决定受到了向后兼容性问题的影响,也许还有维护代码库的难易程度。如果您想在这一点上得到明确的答案,您可能不得不询问 PyQt 的作者。

问题的另一个(更大)部分在于,当层次结构中的某些类本质上是不合作的(例如,因为它们是用 C++ 编写的,就像 Qt 一样)时,如何让协作多继承工作。我认为在某种程度上解决这些问题是可能的——PyQt 至少已经为类构造做到了这一点(参见Support for Cooperative Multi-inheritance)。但是对于像 Qt 这样的大型库来说,这样做显然是一项更大的任务。我想总会有一些皱纹(就像你发现的那样)永远不会完全消除。

于 2017-10-06T20:23:06.427 回答