Christian O'Reilly
Christian O'Reilly

Reputation: 2054

Python error "TypeError: could not convert X to Y" in multiple inheritance

I've translated in Python/PyQt a code that was working fine in C++/Qt and I don't understand why it now generates an error. Here is a minimal code reproducing the problem:

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class A(QFrame): 
    def __init__(self, parent) :
        QFrame.__init__(self, parent)    


class B(A, QLine):
    def __init__(self, parent) :
        A.__init__(self, parent)
        QLine.__init__(self, parent)

class C(B):

    def __init__(self, parent) :
        B.__init__(self, parent)
        self.setLine(0, 0, 0, 0)



if __name__ == "__main__":

    app     = QApplication(sys.argv)
    myApp   = QMainWindow()
    myApp.show()

    c = C(myApp)

    sys.exit(app.exec_())    

When running this code, I get the message "TypeError: could not convert 'C' to 'QLine'"... Why is that so? What is the problem? How to get around?

Upvotes: 1

Views: 538

Answers (1)

abarnert
abarnert

Reputation: 365945

According to various other posts, you cannot inherit from QObject twice.

They all link to http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/gotchas.html#multiple-inheritance, which I can no longer find. But Things to be Aware Of in the PyQt 4.10.2 Reference Guide says:

It is not possible to define a new Python class that sub-classes from more than one Qt class.

Quoting one of the answers:

The limitation doesn't come from python or PyQt. Its purely because of Qt and means that you can not inherit from multiple classes that are or inherit from QObject.

According to other answers, it's apparently not that it's impossible in Qt, it's that it doesn't do what you expect in C++ unless you use virtual inheritance (which causes other problems with Qt), so PyQt4 blocks it. In particular, in your example, C isn't really properly a QFrame, but as long as you never use any QFrame virtual methods, or any functions that depend on members that QFrame inherited from QObject, you will happen to get away with it.


Anyway, there seems like an obvious workaround here. What you need is "C must be of the same type as A (for practical reasons)". You can get that by splitting A up:

class AMixin(object):
    def __init__(self, parent):
        pass
    # A-specific behavior

class A(QFrame, AMixin):
    def __init__(self, parent) :
        QFrame.__init__(self, parent)
        A.__init__(self, parent)


class B(AMixin, QLine):
    def __init__(self, parent) :
        AMixin.__init__(self, parent)
        QLine.__init__(self, parent)

class C(B):
    def __init__(self, parent) :
        B.__init__(self, parent)
        self.setLine(0, 0, 0, 0)

Now C and A have the relationship you (probably) want, but C only has one QObject ancestor, so everything is good.

Upvotes: 2

Related Questions