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 should probably stick to new style, and use super. 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. 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. 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). 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. 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. regards, herman -- http://mail.python.org/mailman/listinfo/python-list