[PyQt] Issue with multiple inheritance

Martin Teichmann lkb.teichmann at gmail.com
Sat Jan 21 14:26:17 GMT 2017


Hi everybody,

> I am trying to write a class that inherits from two parent classes: one from
> Qt and one mine.

Interestingly, your minimal example works for me. I would still like
to elaborate a bit on it.

You actual problem is that your inheritance order is wrong. While
Python supports multiple inheritance, its C backend does not. Because
of this, you inherit from a Python base class that overrides methods
from a C base class, but not the other way around, a class written in
C will call its inherited methods, you cannot override that.

In Python, base classes mentioned first take priority over those
mentioned last, so given that you can technically (!) only override C
methods by Python methods, classes implemented in C always go last in
the inheritance list. (You can only have one of them, so there is no
doubt).

As an example, take the builtin class dict, which is written in C, and
another class that overrides, say __getitem__. Such a class is
traditionally called a Mixin class:

    class Mixin:
        def __getitem__(self, item):
              print('trying to get', item)
              return super().__getitem__(item)

    class MySuperDict(Mixin, dict):
        pass  # add some cool stuff here

now Mixin.__getitem__ overrides dict.__getitem__ in MySuperDict. Note that

   class MySuperDict(dict, Mixin): # don't do that!

does not work. dict won't even bother about the existence of the Mixin
base, as it is written in C and doesn't know anything about it, so
Mixin.__getitem__ will never be called.

So, in short: when programming Python, always put your own Python
mixin classes first in the inheritance list.

In PyQt, however, Phil didn't like that, because it doesn't look like
C++ code. Why anyone writing Python would like their code to look like
C++ I don't know, but apparently there are people out there. So Phil
went at great length to change the internals of the Python inheritance
model, only so that you can write

    class MyObject(QObject, Mixin):  # don't do that!

There is, however, no good reason to do so. You can, without any
problems, simply go with good Python style and write

    class MyObject(Mixin, QObject):

and everything works as expected.

You might now say: but I am not trying to override anything! You are.
You are trying to override __init__. And for it to work properly, I
would always recommend to use the super() mechanism, not calling the
base class directly.

As a side note: the reason things need to be written differently in
C++ than in Python are because in those languages multiple inheritance
means something completely different. The overriding in a mixin class
as described above doesn't exist in C++. On the other hand, C++ has a
complex system to assure consistent memory layouts in multiple
inheritance. Python does not support that at all, once you're
discussing about memory layout, there is not multiple inheritance
anymore, which eliminates that problem.

Greetings

Martin


More information about the PyQt mailing list