[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