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