pyqt 类的方法解析顺序是什么?



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

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

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

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

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'>

这不是一个bug。这里的差异完全是由于实现细节造成的,我不会试图解释这些细节(即使我可以解释)。PyQt很可能会更改其实现,使其与Python行为更加紧密地一致。但它选择了妥协,并没有偏离Qt/C++中的工作方式太远。我想这个决定受到了向后兼容性问题的影响,也许还有维护代码库的容易性。如果你想在这一点上得到一个明确的答案,你可能不得不问PyQt的作者。

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

相关内容

  • 没有找到相关文章

最新更新