Calling __init__ for all mixins
Shalabh Chaturvedi
shalabh at cafepy.com
Wed Aug 18 17:58:14 EDT 2004
Martin Maney wrote:
> I've been to the cookbook (both forms, since they're sometimes usefully
> different), but that gave rise to more questions than answers. Heck,
> let me pull some of them up while I'm at it.
>
> Martelli gives the recipie (5.3 on paper) "Calling a Superclass
> __init__ Method if it Exists" where he seems to say that this:
>
> class NewStyleOnly(A, B, C):
> def __init__(self):
> super(NewStyleOnly, self).__init__()
>
> is the New Class Speak equivalent of
>
> class Classic(A, B, C):
> def __init__(self):
> for base in self.__class__.__bases__:
> if hasattr(base, '__init__'):
> base.__init__(self)
>
> but when I tried a simple test case (base classes just print a tracer
> when called), Martelli's NewStyleOnly only invoked A.__init__, as it
> was the first base class in the base list as written with an __init__
> implemented. These seem to me to be very different.
>
<snipped unrelated problem>
> So the reason I was turning over these stones was that I'm working on a
> subsystem where I want to compose working classes using multiple mixin
> base classes to provide different implementations for separate parts of
> the interface. So far this is working quite nicely (1), but the
> business of calling all the mixins' __init__ functions is a bit of a
> nuisance. Unfortunately, the solutions I've found (aside from
> Martelli's NewStyleOnly which I'm sure was only accidentally implied to
> be a solution to this problem) all seem little is any better than the
> simple and obvious method of explicitly invoking each one. I'm not
> certain that I won't need to use that manual approach in the end, since
> the current draft has a couple of arguments to one mixin, and it's not
> clear I can eliminate them, but I would still be interested in any
> suggestions for nicer solutions to the MI __init__ problem.
The new-style super mechanism might indeed solve your problem. In the
snippet that you mention, super(NewStyleOnly, self).__init__() would
only call A.__init__(). But A.__init__ should itself have a super call
of the form:
def __init__(self):
super(A, self).__init__() # A's super call
Now *that* will call B.__init__(), which should itself have a super call
of the form - you guessed it:
def __init__(self):
super(B, self).__init__()
Which will call C.__init__(). And so on. Also note that super() will
work correctly in the case you had a class:
class AnotherClass(A, C):
def __init__(self):
super(NewStyleOnly, self).__init__()
In this case, A's super call would call C.__init__(). Nice, huh?
This is the cooperative super call technique explained in the following
places:
http://www.python.org/2.2.3/descrintro.html#cooperation
http://www.cafepy.com/articles/python_attributes_and_methods/ch02.html
Any class wanting to participate in this technique must be new-style.
Cheers,
Shalabh
More information about the Python-list
mailing list