Brian gave a good example, so I refer you to that.
Until somebody else comes along and creates class E that inherits from
both C and D and also uses super(), and now suddenly the super() call
in C becomes equivalent to "D.method(*args)" instead for instances of
E, potentially with unexpected results. Or worse, E.method
incorrectly calls both C.method and D.method explicitly, and now
D.method gets invoked twice, once implicitly from C.method, and once
explicitly from E.method.
I realize that it is the responsibility of the person writing class E
to make sure they're working with class C correctly, but in order for
them to do that, ultimately every method in class C should be
documented as to whether it calls super() or not, and if so whether it
is designed only for single inheritance or with the MRO in mind. That
really shouldn't be necessary,
I was with you up to here.
It's *manifestly* necessary. One cannot inherit from a class reliably
without knowing how it's implemented. Knowing the interface is not
enough. This is not limited to multiple inheritance; it happens with
single inheritance as well, just less often. It's not limited to
Python, this is true of Java, C++, and every other OOP language I know
of.
Take list. Say you want a singly inherit from list to implement some
kind of observer that emits a signal every time an item is set. How
do you do it? You can't tell by looking at the interface. Do you
only have to override __setattr__? Or do you also have to override
other methods (insert, append, etc)? That depends on whether insert
et al. call __setattr__ or operate at a lower level. You can't tell
simply by looking at the interface. You have to have knowledge of the
internals of list.
It's the same problem with multiple inheritance, only exacerbated.
The issues with super is a new dimension, but it's the same problem:
you have to know what you're inheriting from.
This is a fundamental issue with all inheritance.
The problem, in my mind, is that people use inheritance for stuff that
doesn't need it.
class MyFoo(SomebodyElsesFoo):
def my_tacked_on_method(self):
self.call_this_method()
self.then_call_that_method()
Unnecessary and risky. Do this:
my_tacked_on_function(foo):
foo.call_this_method()
foo.then_call_that_method()
The only reason to inherit in a situation like this is if you need
polymorphism (you want to pass your MyFoo to a function that operates
on objects that define a my_tacked_on_method).
A lot Michele Simionato's objections to inheritance are based on the
idea that you don't necessarily know what you're inheriting from. I
say, if you don't know what you're inheriting from, you shouldn't be
inheriting. I say this as a strong proponent of inheritance and
multiple inheritance in particular. I believe it's the best way in
general for objects of different types to share large portions of
their behavior. But it has its place.
When you have a class you that don't anything about the implementation
of, that is NOT the place for inheritance. In that case you should
either use composition, or learn what it is you're inheriting from and
take responsibility if the owner changes it. Or just don't try to
share behavior.
My view of inheritance is a lot like the orthodox Catholic view of
sex. To Catholics, sex between married people is a wonderful, holy
thing. To me, inheriting from classes you know the implementation of
is a wonderful, holy thing. But, sex outside of marriage, and
inheriting from classes you don't know, is deadly sin and you will
burn in Hell.
and in my current view from a
maintenance perspective, best practice is to only use super() in the
multiple-inheritance scenarios it was specifically designed for
I use super() exclusively for all types of inheritance, unless I'm
inheriting from a class I know uses old form (which is none of mine,
and I only rarely inherit from classes I don't own).
Carl Banks