invoking a method from two superclasses

Mitchell L Model MLMLists at Comcast.net
Wed Jul 1 05:39:16 CEST 2009


>From: Scott David Daniels <Scott.Daniels at Acm.Org>
>Date: Tue, 30 Jun 2009 16:49:18 -0700
>Message-ID: <ieudnfm_J89EP9fXnZ2dnUVZ_g6dnZ2d at pdx.net>
>Subject: Re: invoking a method from two superclasses
>
>Mitchell L Model wrote:
>>In Python 3, how should super() be used to invoke a method defined in C
> > that overrides its two superclasses A and B, in particular __init__?
>>...
>>I've discovered the surprising fact described in the documentation of super
>><http://docs.python.org/3.1/library/functions.html#super>
>>that specifying a class as the first argument of super means to skip that class when
>>scanning the mro so that ....
>>
>>This seems weird. Would someone please give a clear example and explanation of
>>the recommended way of initializing both superclasses in a simple multiple inheritance
>>situation?
>
>OK, in Diamond inheritance in Python (and all multi-inheritance is
>diamond-shaped in Python), the common ancestor must have a method
>in order to properly use super.  The mro is guaranteed to have the
>top of the split (C below) before its children in the mro, and the
>join point (object or root below) after all of the classes from
>which it inherits.
>
>So, the correct way to do what you want:
>    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:
>
>    class root:
>        def prints(self):
>            print('root') # or pass if you prefer
>
>    class A(root):
>        def prints(self):
>            super().prints()
>            print('A')
>
>    class B(root):
>        def prints(self):
>            super().prints()
>            print('B')
>
>    class C(A, B):
>        def prints(self):
>            super().prints()
>            print('C')
>
>    C().prints()
>
>--Scott David Daniels
>Scott.Daniels at Acm.Org
>

Great explanation, and 1/2 a "duh" to me. Thanks.
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. Is this what the documentation means by
"cooperative multiple inheritance"?

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.

It would appear that "super()" really means something like CLOS's call-next-method.
I've seen various discussions in people's blogs to the effect that super() doesn't really
mean superclass, and I'm beginning to develop sympathy with that view. I realize that
implementationally super is a complicated proxy; understanding the practical
implications isn't so easy. While I've seen all sorts of arguments and discussions,
including the relevant PEP(s), I don't think I've ever seen anyone lay out an example
such as we are discussing with the recommendation that basically if you are using
super() in multiple inheritance situations, make sure that the methods of all the classes
in the mro up to at least the top of a diamond all call super() so it can continue to
move the method calls along the mro. The documentation of super(), for instance,
recommends that all the methods in the diamond should have the same signature, but
and it says that super() can be used to implement the diamond, but it never actually
comes out and says that each method below the top must call super() at the risk
of the chain of calls being broken.  I do wonder whether this should go in the doc
of super, the tutorial, or a HOWTO -- it just seems to important and subtle to leave
for people to discover.

Again, many thanks for the quick and clear response.



More information about the Python-list mailing list