Multiple inheritance order in Python3/PyQt

2019-08-31 15:47发布

问题:

I met an issue when using multi inheritance with PyQt, the Programe 1# source code as below:

#!python3
import sys;
from PyQt5.QtWidgets import *;
from PyQt5.QtGui import *;
from PyQt5.QtCore import *;

class WP_Widget(QWidget):
    def __init__(self):
        print("WP_Widget init");
        super().__init__();

class WP_Line(QLineEdit):
    def __init__(self, text='',*args, **kargs):
        super().__init__();
        self.setText(text);

class Widget_C(WP_Widget, WP_Line):
#class Widget_C(WP_Line, WP_Widget):
    def __init__(self):
        print('Widget_C self = ', self)
        super().__init__();

class App(QWidget):
    def __init__(self):
        super().__init__();
        fname = Widget_C();
        self.left = 100
        self.top = 100
        self.width = 100
        self.height = 100
        self.show();

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())

When execute, it will show the error as:

AttributeError: 'Widget_C' object has no attribute 'setText'

If change Widget_C definition from

class Widget_C(WP_Widget, WP_Line):

to

class Widget_C(WP_Line, WP_Widget):

It will run successfully.

I guess it will be related to MRO in Python3, so I write another program 2# to simulate the state:

#!python3

class QWidget():
    def __init__(self):
        print("Base QWidget init.");

class QLineEdit(QWidget):
    def __init__(self):
        print('LineEdit init');
        super().__init__();

    def setText(self, text):
        print('setText called');

class WP_Widget(QWidget):
    def __init__(self):
        print('WP_Widget Init');
        super().__init__()

class WP_Line(QLineEdit):
    def __init__(self, text='',*args, **kargs):
        print('WP_Line init');
        super().__init__();
        self.setText(text)

class Widget_C(WP_Widget, WP_Line):
#class Widget_C(WP_Line, WP_Widget):
    def __init__(self):
        super().__init__()

c_test = Widget_C()

But no matter which inheriting sequence of Wiget_C,

class Widget_C(WP_Line, WP_Widget):

or

class Widget_C(WP_Widget, WP_Line):

both of them will run normally.

So could anyone help:

  1. Explain why program 1# fails when defined as class Widget_C(WP_Widget, WP_Line):, MRO is just my guess.
  2. Why program 2# can be run normally in both condition ?
  3. Help modify program 2# to reproduce the state of program 1# .

Python and order of methods in multiple inheritance explains something about MRO, it related to my question, but not exactly the answer. If inheriting order is the same, my program 1# and program 2 should not have different results, so the key point is why program 1# and program 2 have different phenomenon.

回答1:

ekhumoro gave the exactly answer what I need.

As stated in the docs, pyqt does not support multiple inheritance of qt classes. Which is to say, it won't work the way you would normally expect it to in normal python.

Having said that, this blog post has some interesting insights and work-arounds (but note that it was originally written for pyqt4, so some things may now be out of date).