On Sun, 23 Jun 2013 12:49:42 -0400, Roy Smith wrote: > One thing I've never understood about Python 2.x's multiple inheritance > (mostly because I almost never use it) is how you do something like > this: > > class Base1(object): > def __init__(self, foo): > self.foo = foo > > class Base2(object): > def __init__(self, bar): > self.bar = bar > > class Derived(Base1, Base2): > def __init__(self, foo, bar): > # now what??? > > I need to call __init__() in both of my base classes. I don't see how > super() can do that for me.
It doesn't, and it can't, because your classes are not cooperative. The problem is, Derived.__init__ needs to call two super methods, but both of them require different arguments. If this was an ordinary method, you'd probably see the flaw straight away: class Artist: def draw(self, painting): ... class Gambler: def draw(self, cards): ... class GamblingArtist(Gambler, Artist): def draw(self, painting, cards): ... Here you've got two completely different actions that merely share the same name, is it really sensible to have *one* method try to do both? And if so, you certainly can't expect an automated call to work out which argument goes to which superclass. So here's a place where cooperative multiple inheritance doesn't work, and you're reduced to either manually calling the methods (and hoping that they don't, in turn, end up in some sort of diamond inheritance diagram, which would be bad), or else you have to redesign your classes to be more cooperative. This is one of the reasons why many languages simply prohibit multiple inheritance outright, except perhaps for mixins, or at least require that all methods have compatible signatures. All is not lost, there are ways to make your classes cooperative. The trick is to have your classes' __init__ methods ignore keyword arguments they don't know what to do with. object used to do the same thing, but it no longer does, so you need to add an extra class just before object to swallow any args before they read object. class Blocker(object): def __init__(self, **kwargs): # Block kwargs from reaching object super(Blocker, self).__init__() class Base1(Blocker): def __init__(self, foo, **kwargs): self.foo = foo super(Base1, self).__init__(**kwargs) class Base2(Blocker): def __init__(self, bar, **kwargs): self.bar = bar super(Base2, self).__init__(**kwargs) class Derived(Base1, Base2): def __init__(self, foo, bar): super(Derived, self).__init__(foo=foo, bar=bar) This may seem like a lot of work, but nobody said that cooperative multiple inheritance with different method signatures was easy! The reality is, multiple inheritance is *hard*. Mixins and traits remove most of the problems, so if all you've ever used MI for is mixing in new behaviour, you won't get just how hard it really is. The best way to do MI is not to do it at all. But if you have to use it, then super is the only way to do it *right*. Anything else, and you're almost certainly either duplicating what super would do, or you've got bugs in your code. Anyway, here are some links about super: Super considered Super: http://rhettinger.wordpress.com/2011/05/26/super-considered-super/ Here's a set of three posts, written quite a long time ago but still relevant, dissecting super in gory detail: http://www.artima.com/weblogs/viewpost.jsp?thread=236275 http://www.artima.com/weblogs/viewpost.jsp?thread=236278 http://www.artima.com/weblogs/viewpost.jsp?thread=237121 and a more recent update: http://www.artima.com/weblogs/viewpost.jsp?thread=281127 and a counter-argument, provocatively titled "Super considered Harmful", although the author backs away from this claim, since it turns out that the problems are not *super* but multiple inheritance itself. https://fuhm.net/super-harmful/ Despite telling people not to use super, James Knight doesn't actually give them a better alternative. I believe this is because he can't -- super is the worst solution to multiple inheritance except for all the others. -- Steven -- http://mail.python.org/mailman/listinfo/python-list