invoking a method from two superclasses

Scott David Daniels Scott.Daniels at Acm.Org
Wed Jul 1 11:38:58 EDT 2009


 > Mitchell L Model wrote:

Sorry, after looking over some other responses, I went back and re-read
your reply.  I'm just making sure here, but:

 > Scott David Daniels wrote:
Below compressed for readability in comparison:
>>    class A:
>>        def __init__(self): super().__init__(); print('A')
>>    class B:
>>        def __init__(self): super().__init__(); print('B')
>>    class C(A, B):
>>        def __init__(self): super().__init__(); print('C')
>>    C()
>> And, if you are doing it with a message not available in object:

Renamed to disambiguate later discussion
>>    class root:
>>        def prints(self): print('root') # or pass if you prefer
>>    class D(root):
>>        def prints(self): super().prints(); print('D')
>>    class E(root):
>>        def prints(self): super().prints(); print('E')
>>    class F(D, E):
>>        def prints(self): super().prints(); print('F')
>>    F().prints()

> What I was missing is that each path up to and including the top of the diamond
> must include a definition of the method, along with super() calls to move the method
> calling on its way up.

Actually, not really true.  In the F through root example, any of the
"prints" methods except that on root may be deleted and the whole thing
works fine.  The rootward (closer to object) end must contain the method
in question, possibly only doing a pass as the action, and _not_ calling
super.  The other methods (those in D, E, and F above are all optional
(you can freely comment out those methods where you like), but each
should call super() in their bodies.

Note that you can also add a class:
     class G(E, D):
         def prints(self): super().prints(); print('G')
     G().prints()
Also note that the inheritances above can be "eventually inherits from"
as well as direct inheritance.

> Is this what the documentation means by "cooperative multiple inheritance"?

Yes, the phrase is meant to convey "No magic (other than super itelf) is
involved in causing the other methods to be invoked.  If you want "all"
prints methods called, make sure all but the last method do super calls.
Of course, any method that doesn't do the super call will be the last by
definition (no flow control then), but by putting the non-forwarding
version at or below the lower point of the diamond, the mro order
guarantees that you will have a "good" place to stop.

Think of the mro order as a solution to the partial order constraints
that a class must appear before any of its direct superclasses, and (by
implication) after any of its subclasses.

> If your correction of my example, if you remove super().__init__ from B.__init__
> the results aren't affected, because object.__init__ doesn't do anything and
> B comes after A in C's mro. However, if you remove super().__init__ from
> A.__init__, it stops the "supering" process dead in its tracks.

Removing the super from B.__init__ means that you don't execute
object.__init__.  It turns out that object does nothing in its __init__,
but without knowing that, removing the super from B.__init__ is also a
mistake.

So, you may well already have it all right, but as long as I'm putting
in the effort to get the "operational rules about using super" out, I
thought I'd fill in this last little bit.

--Scott David Daniels
Scott.Daniels at Acm.Org



More information about the Python-list mailing list