super() and multiple inheritance

Carl Banks invalidemail at aerojockey.com
Thu Dec 1 18:12:15 EST 2005


hermy wrote:
> Thanx, I think I got it (please correct me if I'm wrong):
> o super(C,self) determines the next class in the inheritance hierarchy
> according to
>   method resolution order, and simply calls the specified method on it
> (in this case
>  __init__ with the specified argument list.
> o since I cannot now beforehand where my class will appear in the
> inheritance
>   hierarchy when __init__ is called, I need to pass on all the
> arguments and let
>   my method decide which ones to use.
>
> On the other hand, when I use old-style, s.a. B.__init__(args), I
> specify statically
> in which class the method lookup should occur.
>
> Unfortunately, new and old style don't mix well (as I found out by
> experimenting a little),
> so for new code I should probably stick to new style, and use super.

Well I wasn't suggesting you mix styles; I was suggesting all old, all
the way here.  With due care, the effect of using this style over the
entire hierarchy is to call the __init__ functions possibly out of MRO
sequence.  You have to pay some attention to what methods are called in
__init__ anyways, so this isn't exactly a whole new dimension of
carefulness.

> Which leads me to my original problem. Your suggestion with **kwargs
> works fine,
> but only if it's used consistently, and I'll probably need to do some
> name-mangling
> to encode class names in parameter names in order to avoid name
> clashes.

Meh.  Do nameclashes happen so often that it's better to implement a
handmade name mangling scheme rather than just change a variable name
when one pops up?

> Unfortunately, this solution is (as far as I know) not universally
> accepted, so if I want
> to multiply inherit from other people's classes (who didn't follow this
> solution), it won't
> work. Short: I can make it work if I write all the classes myself, I
> can't make it work if
> I try to re-use other people's code.

I would suggest that, if you're trying to make a mixin of completely
different classes, super is only one of many worries.  There's all
sorts of things that could go wrong when you do that in Python.  When
you have a class that's not expecting to be in an inheritance
hierarchy, it might not even be calling super.  Or if it's a derived
class, it might be using old-style calls to the subclass.  Sometimes
classes have incompatible C-footprints and can't be mixed in.  Python
objects use a single namespace for their instance variables, so if
these two classes happen to use the same for a variable, you're pretty
much out of luck.  If any of the classes use a different metaclass
there could be all sorts of problems.

Bottom line is: if you're going to multiply inherit from two classes,
they have to cooperate in some fashion.  You have to be careful, and
sometimes you can't avoid modifying the base classes.  (Yes, you can do
that.)

> Which is a pity, since this means that I can't even use multiple
> inheritance for mixin
> classes (where I know that no diamond will appear in the hierarchy, and
> I have a simple
> tree - except for the shared object superclass).

Um, sure you can.  You can't necessarily, but it doesn't mean you can't
never.

> So, for the moment my conclusion is that although Python has some
> syntax for
> multiple inheritance, it doesn't support it very well, and I should
> probably stick to
> single inheritance.

"well supported" is a relative term.  I don't disagree that MI can be
unwieldy in Python, but it seems to me that throwing it out of the
toolshed is a bit extreme here.  There's just times when MI is the best
and most elegant solution to a problem, and not using it because you
have to fiddle with __init__ args a little is probably not a good
thing.

> Also, if there would be some language support for the argument passing
> problem
> (especially for __init__ methods), multiple inheritance would work just
> fine. Hopefully
> some future version of Python will solve this.

Not likely at all.  I think the Python philosophy is that MI is a thing
that's occasionally very useful, but not vital.  I think the designers
feel that a little unwieldiness in MI is a small price to pay compared
the language changes needed to take away that unwieldiness.  For
instance, a foolproof way to avoid name clashes in mixin classes would
require a complete overhaul of namespaces in Python, and that is not
going to happen.

At best, what you might get is some sort of protocol (maybe a
decorator) that standardizes calling the base class methods, coupled
with a very strong suggestion to use it in all future code for all
classes.


Carl Banks




More information about the Python-list mailing list