>From: Scott David Daniels <scott.dani...@acm.org> >Date: Tue, 30 Jun 2009 16:49:18 -0700 >Message-ID: <ieudnfm_j89ep9fxnz2dnuvz_g6dn...@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.dani...@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. -- http://mail.python.org/mailman/listinfo/python-list