[newbie] super() and multiple inheritance

2005-12-01 Thread hermy
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) { ... }

I'm probably overlooking some basic stuff here, but I haven't
been able to figure this out. Googling got me lots of examples,
but all with empty __init__ argument lists (which obviously works,
but is too trivial in practice).

regards,
herman
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: super() and multiple inheritance

2005-12-01 Thread hermy

Carl Banks schreef:

> 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

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