Builtn super() function. How to use it with multiple inheritance? And why should I use it at all?

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Thu Jul 29 08:55:53 EDT 2010


On Thu, 29 Jul 2010 12:08:54 +0200, Jean-Michel Pichavant wrote:

> Steven D'Aprano wrote:

>> That incorrect. You can certainly use super() with classic classes in
>> the hierarchy, and super() didn't even exist when they were created.
>> The problem isn't super(), and people who give glib advise "don't use
>> super()" are just compounding the problem. The problem is with multiple
>> inheritance where methods have different method signatures. If you
>> don't change the method signatures, super() will work fine.
[...]
> I think you're missing the point that super for most of us is a
> dangerous guess game. It makes implicit what would *really* need to be
> explicit.

No, I'm not missing the point. I'm *disagreeing* with the point. I'm 
saying that for simple inheritance hierarchies, super() does no harm, and 
it is *required* for most complex inheritance hierarchies. Given that, 
why not use it? 

I suppose that, if you're inheriting from an existing class which doesn't 
use super(), there may be issues (although I'm not convinced that those 
issues go away if you avoid super!) but for a new class under your 
control, there are no negatives to super() that didn't already exist with 
the nature of multiple inheritance.

There is, as far as I can tell, ONE use-case where super() must be 
avoided, and that is a use-case that is discouraged for other reasons: 
where you change the method signature. If you're changing the method 
signature, you're already in dubious territory and better know what 
you're doing. You're violating the Liskov Substitution Principle, and if 
so, you better have a good reason. (I'm a bit skeptical about the LSP, 
but many people much smarter than I think it's virtually gospel, so who 
knows?) But either way, if you change the method signature, you're going 
to have problems somewhere unless you've really careful. The problems 
with super() are merely symptoms of that change.

If you don't change the method signature, then I don't believe super() 
does any harm, regardless of whether you have single inheritance or 
multiple inheritance, whether it is a diamond diagram or not. The worst 
that can be said about it is that super()'s signature is hard to 
understand.

I would argue that your argument about "explicit" and "implicit" is 
incorrect. You shouldn't want to explicitly specify which class you are 
inheriting from, at least not under normal circumstances. It is enough to 
say that you are inheriting behaviour. If you have a Widget class, and 
you find yourself explicitly calling methods by *named* superclasses, 
you're probably doing something wrong.

It should always be possible to insert a class higher up the hierarchy, 
or rename a grandparent, without effecting your class. (Obviously you 
can't expect to rename an immediate parent class.)

super() is just as explicit as len(), or str.upper(). It says, 
explicitly, that it will call the method belonging to one or more 
superclass of the given class. That's no more implicit than mylist[5] is 
implicit merely because you didn't have to walk the list by hand.



> class Base1(object):
>     def foo(self):
>        print 'Base1'
> 
> 
> class Base2(object):
>     def foo(self):
>        print 'Base1'
> 
> 
> class Sub(Base1, Base2):
>     def foo(self):
>            # which  base version to call ???
>            # choice A
>                  # use super an pray that it will do what I need (better
> know exactly how the MRO works)

But the point is, super() knows exactly how the MRO works, so you don't 
have to.


>                  # also pray that further readers know as much as I do
> about super

Now that's just silly. Do you write all your classes for the lowest 
common denominator? Do you assume all you users are ignorant? If you 
subclass dict, do you feel the need to "pray" that your users won't try 
to use mutable objects as keys?

If you avoid super(), do you "pray" that your users won't try to use your 
class in a multiple inheritance situation, and have a buggy class? I bet 
you don't. If they misuse your class, that's their responsibility.



>            # choice B
>                  # use explicit calls so I can choose which algorithm I
> want to use, calling Base1, Base2 or both of them

That's a fair point.

super() uses the standard MRO algorithm, it isn't a "Do What I Mean" mind-
reading function. If you want an unusual MRO, then you're responsible for 
managing it yourself. Go right ahead, this is Python and you have all the 
tools to do so. Nothing forces you to inherit behaviour from the 
superclasses at all -- super() is designed for overloading (extending) 
the behaviour of methods, and so the assumption is that you want to call 
the method in each superclass. But if you're overriding the method 
instead, or doing something unusual, then you're in charge.



>                  # If the choice is too difficult, that means one thing
> => my inheritance design is crap => rewrite it properly.
> 
> Super is known for being required for diamond inheritance, and this
> reputation is well earned. Outside this scope, super's not required.

Of course it's not required. Nor does it do any harm. Far from it -- your 
single inheritance subclass might be just what another user needs for a 
multiple inheritance class, and by not using super(), you ruin it for him.



-- 
Steven



More information about the Python-list mailing list