Cooperative multi-inheritance works with __init__ but not with __new__

Phil Thompson phil at riverbankcomputing.com
Sat Jan 30 17:15:32 GMT 2021


On 29/01/2021 20:26, Russell Warren wrote:
> The PyQt5 cooperative multi-inheritance is implemented for __init__, 
> but
> not for __new__.  It looks like one or all of PyQt5.QtCore.QObject,
> sip.wrapper, and.or sip.simplewrapper don't cooperate by invoking
> super().__new__.
> 
> Can this be addressed in PyQt, or is there a fundamental reason that
> calling super().__new__ is omitted?
> 
> Below is code that demonstrates the problem. You can see that __init__ 
> is
> properly invoked via super()'s MRO chain, but __new__ gets blocked by 
> (at
> least) one of the three mentioned classes. They all should invoke
> super().__new__ in order to cooperate properly.
> 
> This can be worked around by being careful with ordering of bases as 
> shown
> (or probably with an adapter class), but it would be nice if PyQt fully
> supported cooperative multi inheritance here.
> 
> The code:
> 
> ```
> from PyQt5 import QtCore
> 
> class Mixin:
>     def __new__(cls, *args, **kwargs):
>         print("Called Mixin.__new__")
>         self = super().__new__(cls, *args, **kwargs)
>         return self
> 
>     def __init__(self, age = 0, **kwargs):
>         print("Called Mixin.__init__")
>         super().__init__(**kwargs)
> 
> class MyQObject_bad(QtCore.QObject, Mixin): pass
> class MyQObject_good(Mixin, QtCore.QObject): pass
> 
> print("Showing MyQObject_good example:")
> good = MyQObject_good()
> 
> print("\nShowing MyQObject_bad example (Mixin.__new__ not called!):")
> bad = MyQObject_bad()
> 
> print("\nMROs (to show that Mixin.__new__ gets blocked):")
> sep = "\n - "
> print(f"Good MRO:{sep}{sep.join(cls.__name__ for cls in
> MyQObject_good.__mro__)}")
> print(f"Bad MRO: {sep}{sep.join(cls.__name__ for cls in
> MyQObject_bad.__mro__)}")
> ```
> 
> Output of the above script looks like this:
> 
> ```
> Showing MyQObject_good example:
> Called Mixin.__new__
> Called Mixin.__init__
> 
> Showing MyQObject_bad example (Mixin.__new__ not called!):
> Called Mixin.__init__
> 
> MROs (to show that Mixin.__new__ gets blocked):
> Good MRO:
>  - MyQObject_good
>  - Mixin
>  - QObject
>  - wrapper
>  - simplewrapper
>  - object
> Bad MRO:
>  - MyQObject_bad
>  - QObject
>  - wrapper
>  - simplewrapper
>  - Mixin
>  - object
> ```

I'm not sure how you expect this to work. Cooperative multi-inheritance 
is only really useful for methods that don't return a result. You can't 
assume that the last type in the MRO is the one that actually creates 
the object (and therefore all preceding types can simply return the 
value returned by their call to super()). simplewrapper.__new__() has 
created the object so why would it call a super-class implementation?

Phil


More information about the PyQt mailing list