[Python-Dev] Re: super() harmful?

James Y Knight foom at fuhm.net
Thu Jan 6 00:00:38 CET 2005


On Jan 5, 2005, at 1:23 PM, Guido van Rossum wrote:
>> The issue of mixing super() and explicit calls to the superclass's
>> method occur with any method. (Thus making it difficult/impossible for
>> a framework to convert to using super without breaking client code 
>> that
>> subclasses).
>
> Well, client classes which are leaves of the class tree can still
> safely use BaseClass.thisMethod(self, args) -- it's only classes that
> are written to be extended that must all be converted to using
> super(). So I'm not sure how you think your clients are breaking.

See the section "Subclasses must use super if their superclasses do". 
This is particularly a big issue with __init__.

>> Adding optional arguments to one branch of the inheritance tree, but
>> not another, or adding different optional args in both branches.
>> (breaks unless you always pass optional args as keywordargs, and all
>> methods take **kwargs and pass that on to super).
>
> But that breaks anyway; I don't see how using the old
> Base.method(self, args) approach makes this easier, *unless* you are
> using single inheritance. If you're expecting single inheritance
> anyway, why bother with super()?

There is a distinction between simple multiple inheritance, which did 
work in the old system vs. multiple inheritance in a diamond structure 
which did not work in the old system. However, consider something like 
the following (ignore the Interface/implements bit if you want. It's 
just to point out a common situation where two classes can 
independently implement the same method without having a common 
superclass):

class IFrob(Interface):
   def frob():
     """Frob the knob"""

class A:
   implements(IFrob)
   def frob(self, foo=False):
     print "A.frob(foo=%r)"%foo

class B:
   implements(IFrob)
   def frob(self, bar=False):
     print "B.frob(bar=%r)"%bar

class C(A,B):
   def m(self, foo=False, bar=False):
     A.m(self, foo=foo)
     B.m(self, bar=bar)
     print "C.frob(foo=%r, bar=%r)"%(foo,bar)

Now, how do you write that to use super? Here's what I come up with:

class IFrob(Interface):
   def frob():
     """Frob the knob"""

class A(object):
   implements(IFrob)
   def frob(self, foo=False, *args, **kwargs):
     try:
       f = super(A, self).frob
     except AttributeError:
       pass
     else:
       f(foo=foo, *args, **kwargs)
     print "A.frob(foo=%r)"%foo

class B(object):
   implements(IFrob)
   def frob(self, bar=False, *args, **kwargs):
     try:
       f = super(B, self).frob
     except AttributeError:
       pass
     else:
       f(bar=bar, *args, **kwargs)
     print "B.frob(bar=%r)"%bar

class C(A,B):
   def frob(self, foo=False, bar=False, *args, **kwargs):
     super(C, self).frob(foo, bar, *args, **kwargs)
     print "C.frob(foo=%r, bar=%r)"%(foo,bar)



> And using multiple inheritance the old was was not confusing? Surely
> you are joking.

It was pretty simple until you start having diamond structures. Then 
it's complicated. Now, don't get me wrong, I think that MRO-calculating 
mechanism really is "the right thing", in the abstract. I just think 
the way it works out as implemented in python is really confusing and 
it's easy to be worse off with it than without it.

> If they're happy with single inheritance, let them use super()
> incorrectly. It works, and that's what count. Their code didn't work
> right with multiple inheritance before, it still doesn't. Some people
> just are uncomfortable with calling Base.method(self, ...) and feel
> super is "more correct". Let them.

Their code worked right in M-I without diamonds before. Now it likely 
doesn't work in M-I at all.

James



More information about the Python-Dev mailing list