[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().)
-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to