invoking a method from two superclasses

Mitchell L Model MLMLists at Comcast.net
Wed Jul 1 00:57:13 EDT 2009


[Continuing the discussion about super() and __init__]

The documentation of super points out that good design of diamond patterns require the methods to have the same signature throughout the diamond. That's fine for non-mixin classes where the diamond captures different ways of handling the same data. The classical example is 

	BufferedStram
	     / \
	  /       \
	/           \
     BufInputStrm    BufOutputStrm		both have buffers, but use them differentlyu
	\            /
 	  \        /
	    \    /
	RandomAccessStream		or something like that

The idea of the diamond is to have just one buffer, rather than the two buffers that would result in C++ without making the base classes virtual.  All four classes could define __init__ with the argument
filename, or whatever, and everything works fine.

The problems start with the use of mixins. In essence, mixins intentionally do NOT want to be part of diamond patterns. They are orthogonal to the "true" or "main" class hierarchy and just poke their heads in hear and there in that hierarchy. Moreover, a class could inherit from multiple mixins. Typical simple orthogonal mixins would be NamedObject, TrackedObject, LoggedObject, ColoredWidget, and other such 
names compounded from an adjective, participle, or gerund and a completely meaningless name such as Object or Thing and which classes typically manage one action or piece of state to factor it out from the many other classes that need it where the pattern of which classes need them does not follow the regular class hierarchy.  Suppose I have a class User that includes NamedObject, TrackedObject, and LoggedObject as base classes. (By Tracked I mean instances are automatically registered in a list or dictionary for use by class methods that search, count, or do other operations on them.)

The problem is that each mixin's __init__ is likely to have a different signature. User.__init__
would have arguments (self, name, log), but it would need to call each mixin class's __init__ with different arguments. Mixins are different than what the document refers to as cooperative multiple inheritance -- does that make them uncooperative multiple inheritance classes :-)? I think I'd be back to having to call each mixin class's __init__ explicitly:

	class User(NamedObject, TrackedObject, LoggedObject)
		def __init__(self, name, log):
			NamedObject.__init__(self, name)
			TrackedObject.__init__(self)
			LoggedObject.__init__(self, log)

This is not terrible. It seems somehow appropriate that because mixin use is "orthogonal" to the "real" inheritance hierarchy, they shouldn't have the right to use super() and the full mro (after all, who knows where the mro will take these calls anyway). And in many cases, two mixins will join into another (a NamedTrackedObject) for convenience, and then classes inheriting from that have one less init to worry about.

I suspect this problem is largely with __init__. All the other __special__ fns have defined argument lists and so can be used with diamond patterns, mixins, etc.

Does this all sound accurate?  (Again, not looking for design advice, just trying to ferret out the subtleties and implications of multiple inheritance and super().)



More information about the Python-list mailing list