Multiple inheritance - How to call method_x in InheritedBaseB from method_x in InheritedBaseA?
The Music Guy
musicguy at alphaios.net
Sat Sep 5 03:46:17 EDT 2009
On Fri, Sep 4, 2009 at 11:23 AM, Scott David
Daniels<Scott.Daniels at acm.org> wrote:
> The Music Guy wrote:
>>
>> I have a peculiar problem that involves multiple inheritance and method
>> calling.
>>
>> I have a bunch of classes, one of which is called MyMixin and doesn't
>> inherit from anything. MyMixin expects that it will be inherited along
>> with one of several other classes that each define certain
>> functionality.
>
> ... <code semi-example> ...
>>
>> This all appears fine at first, but ...
>> One might be tempted to amend MyMixin's method_x so that it calls the
>> parent's method_x before doing anything else:
>>
>> class MyMixin(object):
>> def method_x(self, a, b, c):
>> super(MyMixin, self).method_x(a, b, c)
>> ...
>>
>> ...but of course, that will fail with an AttributeError because
>> MyMixin's only superclass is object, which does not have a method_x.
>
> Here the fix below works.
>
>> The only way I can think to solve the problem would be to implement a
>> method_x for each Foo that calls the method_x for each of the bases:
>
> ...
>>
>> So, does anyone have an idea about how to remedy this, or at least
>> work around it?
>
> The diamond inheritance stuff is meant to allow you to deal with
> exactly this issue. If you define a class, MixinBase, with do-
> nothing entries for all the methods you are inventing, and you
> make all of your Mixin classes (and your main class) inherit
> from MixinBase, you are guaranteed that all of the Mixins you
> use will be earlier on the method resolution order (mro in the
> docs) than MixinBase. If the set of actual methods is small
> and pervasive, I might even be tempted rename MixinBase to
> "Object":
>
>>>> if 1:
> class MixinBase(object):
> '''Base for solving mixin strategy.
>
> Also a nice common place to describe the args and meaning.
> '''
> def method_x(self, a, b, c):
> '''Suitable docstring'''
> print 'MixinBase'
>
> class MyMixin(MixinBase):
> def method_x(self, a, b, c):
> super(MyMixin, self).method_x(a, b, c)
> print 'Mixin'
> class BaseA(MixinBase):
> def method_x(self, a, b, c):
> super(BaseA, self).method_x(a, b, c)
> print 'BaseA'
> class BaseB(MixinBase):
> pass
> class BaseC(MixinBase):
> def method_x(self, a, b, c):
> super(BaseC, self).method_x(a, b, c)
> print 'BaseC'
> class FooX(MyMixin, BaseA):
> def method_x(self, a, b, c):
> super(FooX, self).method_x(a, b, c)
> print 'FooX'
> class FooY(MyMixin, BaseB):
> pass
> class FooZ(MyMixin, BaseC):
> def method_x(self, a, b, c):
> super(FooZ, self).method_x(a, b, c)
> print 'FooZ'
>
>
>>>> FooZ().method_x(1,2,3)
> MixinBase
> BaseC
> Mixin
> FooZ
>>>> FooY().method_x(1,2,3)
> MixinBase
> Mixin
>>>> FooX().method_x(1,2,3)
> MixinBase
> BaseA
> Mixin
> FooX
>>>> BaseA().method_x(1,2,3)
> MixinBase
> BaseA
>>>>
> --Scott David Daniels
> Scott.Daniels at Acm.Org
> --
> http://mail.python.org/mailman/listinfo/python-list
>
Thanks for your reply, Scott. I'm glad there's somebody here who is
actually willing to help me with this; it seems like I usually don't
get any response from posting to most mailing lists. However, I'm not
sure I completely understand your solution.
Two of my requirements are that 1.) no Foo class ever need implement a
method_x because each FooN is merely a version of a BaseN with MyMixin
features added in, and 2.) Each BaseN is a fully-usable class that
does not have MyMixin features and does not need to be subclassed in
order to be used (ie. even though it is usable as a base, it is also
usable as an ordinary class).
Here's some psuedocode that may make my intent more clear:
class Widget(SomeBase, SomeOtherBase, ...):
""" A GUI class that occupies a region of a screen. Can be
contained by a Container class. """
def __init__(self, region):
# Rect-ify the given region (no pun intended)
self.region = Rect(region)
class Container(Widget):
""" A widget that can contain other widgets and show their regions
in relation to the container's region. """
def __init__(self, region, children=()):
Widget.__init__(self, region)
self.children = []
for child in children:
self.append(child)
def __getitem__(self, index):
return self.children[index]
def __setitem__(self, index, new):
self.children[index] = new
def append(self, new):
self.children.append(new)
class MovableContainer(Container):
""" Enhanced container that can be moved in response to the user
clicking and dragging on an empty space in the container. """
...code for handling mouse input...
def append(self, child):
""" Provides enhanced functionality for Container.append. """
super(MovableContainer, self).append(child)
... do some other stuff ...
class LayoutControlMixin(object):
""" A mixin that can be used to add automatic child widget layout
control to existing container classes. """
def append(self, child, **child_layout_config):
""" Same as Container.append or MovableContainer.append, but
allows for optional layout settings specific to each child widget. """
### This is the key line; it should call the `append` method
of the "other" superclass (Container, MovableContainer, etc.) ###
get_other_superclass(self).append(self, child)
...process child_layout_config data, perhaps modify regions of
children...
class LayoutContainer(LayoutControlMixin, Container):
""" A version of Container with layout control. """
pass
class MovableLayoutContainer(LayoutControlMixin, MovableContainer):
""" A version of MovableContainer with layout control. """
pass
More information about the Python-list
mailing list