super() and multiple inheritance

Carl Banks invalidemail at aerojockey.com
Thu Dec 1 13:47:15 EST 2005


hermy wrote:
> Hi,
> I'm trying to figure out how to pass constructor arguments to my
> superclasses in a multiple inheritance situation.
>
> As I understand it, using super() is the preferred way to call
> the next method in method-resolution-order. When I have parameterless
> __init__ methods, this works as expected.
> However, how do you solve the following simple multiple inheritance
> situation in python ?
>
> class A(object):
>      def __init__(self,x):
>          super(A,self).__init__(x)
>          print "A init (x=%s)" % x
>
> class B(object):
>      def __init__(self,y):
>          super(B,self).__init__(y)
>          print "B init (y=%s)" % y
>
> class C(A,B):
>      def __init__(self,x,y):
>          super(C,self).__init__(x,y)  <-------- how to do this ???
>          print "C init (x=%s,y=%s)" % (x,y)
>
> What I want is that when I create a class C object
>     x = C(10,20)
> that the x argument of C's __init__ is used to initialize the
> A superclass, and the y argument is used to initialize the B
> superclass.
> In C++, I would do this using initilaization lists, like:
>     C::C(int x, int y) : A(x), B(y) { ... }

Well, technically, you can't do this in C++ at all.

A little explanation.  In multiple inheritance situations, Python has a
significant difference from regular C++ inheritance: in C++, if you
multiply-inherit from two different classes that both inherit from the
same base class, the resulting structure has two copies of the data
associated with the base class.  In Python, only there is only one
copy.  If you want only one copy of the base class's data in C++, you
must use virtual inheritance.

But here's the thing: in C++, you can't initialize a virtual base class
in the constructor.  A virtual base class is always initialized with
the default constructor.  The reason for this is obvious: otherwise,
you could end up initializing the virtual base twice with different
arguments.

This also explains why, in Python, super is preferred for multiple
inheritance: it guarantees that each base class's __init__ is called
only once.  This comes at the price of less flexibility with the
function arguments, but in Python, at least you can use function
arguments.

So now, let's talk about solutions.

Now that we know why super is preferred, we can make a somewhat
intelligent decision whether to go against the advice.  If you know
your inheritance hierarchy is not going to have any two classes
inheriting from the same base class (except for object), then you could
just call each class's __init__ directly, same as you would have done
with old-style classes.  There is no danger of initializing any base
class twice and no reason for super to be preferred here.

  A.__init__(self,x)
  B.__init__(self.y)

But if you can't or don't want to do this, you'll have to make some
concessions with the argument lists.  One thing to do would have A and
B both accept x and y, using only the one it needs.  A more general
approach might be to use keyword arguments.  For example (you can
improve upon this):

  class A(object):
      def __init__(self,**kwargs):
          use(kwargs['x'])

  class B(object):
      def __init__(self,**kwargs):
          use(kwargs['y'])

  class C(A,B):
      def __init__(self,**kwargs):
          super(C,self).__init__(**kwargs)

  C(x=1,y=2)


> I'm probably overlooking some basic stuff here,

Unfortunately, it doesn't appear that you are.  You'll have to choose
between calling base class __init__s old-style, or fiddling with their
argument lists.


Carl Banks




More information about the Python-list mailing list