Multiple inheritance - How to call method_x in InheritedBaseB frommethod_x in InheritedBaseA?

Discussion in 'Python' started by The Music Guy, Sep 4, 2009.

  1. 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. It defines method_x, which it assumes will also be
    defined in the other class that MyMixin ends up getting inherited
    with. For example,

    class MyMixin(object):
    def method_x(self, a, b, c):
    ...

    class BaseA(object):
    def method_x(self, a, b, c):
    ...

    class BaseB(object):
    def method_x(self, a, b, c):
    ...

    class BaseC(object):
    def method_x(self, a, b, c):
    ...

    class FooX(MyMixin, BaseA):
    ...

    class FooY(MyMxin, BaseB):
    ...

    class FooZ(MyMixin, BaseC):
    ...


    This all appears fine at first, but there is a problem: Each Foo's
    method_x must call the method_x of MyMixin as well as the method_x of
    each respective Foo's second base class. One cannot simply call
    FooN.method_x, because that will only call MyMixin.method_x and not
    that of the other base.

    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.

    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:

    class FooX(MyMixin, BaseA):
    def method_x(self, a, b, c):
    MyMixin.method_x(self, a, b, c)
    BaseA.method_x(self, a, b, c)

    class FooY(MyMxin, BaseB):
    def method_x(self, a, b, c):
    MyMixin.method_x(self, a, b, c)
    BaseB.method_x(self, a, b, c)

    class FooZ(MyMixin, BaseC):
    def method_x(self, a, b, c):
    MyMixin.method_x(self, a, b, c)
    BaseC.method_x(self, a, b, c)


    The problem with this solution is that method_x has to be explicitly
    created for each Foo, even though they all do just about the same
    thing, which kind of defeats the purpose of using multiple inheritance
    in this situation. Besides that, I just don't like it!

    So, does anyone have an idea about how to remedy this, or at least
    work around it?
    The Music Guy, Sep 4, 2009
    #1
    1. Advertising

  2. Re: Multiple inheritance - How to call method_x in InheritedBaseBfrom method_x in InheritedBaseA?

    On Fri, Sep 4, 2009 at 11:23 AM, Scott David
    Daniels<> 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
    >
    > --
    > 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
    The Music Guy, Sep 5, 2009
    #2
    1. Advertising

  3. The Music Guy

    ryles Guest

    Re: Multiple inheritance - How to call method_x in InheritedBaseBfrom method_x in InheritedBaseA?

    On Sep 4, 6:01 am, 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. It defines method_x, which it assumes will also be
    > defined in the other class that MyMixin ends up getting inherited
    > with. For example,
    >
    > class MyMixin(object):
    >     def method_x(self, a, b, c):
    >         ...
    >
    > class BaseA(object):
    >     def method_x(self, a, b, c):
    >         ...
    >
    > class BaseB(object):
    >     def method_x(self, a, b, c):
    >         ...
    >
    > class BaseC(object):
    >     def method_x(self, a, b, c):
    >         ...
    >
    > class FooX(MyMixin, BaseA):
    >     ...
    >
    > class FooY(MyMxin, BaseB):
    >     ...
    >
    > class FooZ(MyMixin, BaseC):
    >     ...
    >
    > This all appears fine at first, but there is a problem: Each Foo's
    > method_x must call the method_x of MyMixin as well as the method_x of
    > each respective Foo's second base class. One cannot simply call
    > FooN.method_x, because that will only call MyMixin.method_x and not
    > that of the other base.
    >
    > 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.
    >
    > 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:
    >
    > class FooX(MyMixin, BaseA):
    >     def method_x(self, a, b, c):
    >         MyMixin.method_x(self, a, b, c)
    >         BaseA.method_x(self, a, b, c)
    >
    > class FooY(MyMxin, BaseB):
    >     def method_x(self, a, b, c):
    >         MyMixin.method_x(self, a, b, c)
    >         BaseB.method_x(self, a, b, c)
    >
    > class FooZ(MyMixin, BaseC):
    >     def method_x(self, a, b, c):
    >         MyMixin.method_x(self, a, b, c)
    >         BaseC.method_x(self, a, b, c)
    >
    > The problem with this solution is that method_x has to be explicitly
    > created for each Foo, even though they all do just about the same
    > thing, which kind of defeats the purpose of using multiple inheritance
    > in this situation. Besides that, I just don't like it!
    >
    > So, does anyone have an idea about how to remedy this, or at least
    > work around it?


    Hopefully I've interpreted your requirement correctly.

    In this particular case a workaround is to use super() in your base
    classes and then have your concrete classes inherit from the base
    *before* the mixin:

    class MyMixin(object):
    def method_x(self, a, b, c):
    print "MyMixin"

    class BaseA(object):
    def method_x(self, a, b, c):
    print "BaseA"
    super(BaseA, self).method_x(a, b, c)

    class FooX(BaseA, MyMixin):
    pass

    FooX().method_x(1, 2, 3)

    BaseA
    MyMixin


    And if you want to define method_x() in FooX, then simply have that
    use super() as well.
    ryles, Sep 6, 2009
    #3
  4. The Music Guy

    Carl Banks Guest

    Re: Multiple inheritance - How to call method_x in InheritedBaseBfrom method_x in InheritedBaseA?

    On Sep 4, 3:01 am, 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. It defines method_x, which it assumes will also be
    > defined in the other class that MyMixin ends up getting inherited
    > with. For example,
    >
    > class MyMixin(object):
    >     def method_x(self, a, b, c):
    >         ...
    >
    > class BaseA(object):
    >     def method_x(self, a, b, c):
    >         ...
    >
    > class BaseB(object):
    >     def method_x(self, a, b, c):
    >         ...
    >
    > class BaseC(object):
    >     def method_x(self, a, b, c):
    >         ...
    >
    > class FooX(MyMixin, BaseA):
    >     ...
    >
    > class FooY(MyMxin, BaseB):
    >     ...
    >
    > class FooZ(MyMixin, BaseC):
    >     ...
    >
    > This all appears fine at first, but there is a problem: Each Foo's
    > method_x must call the method_x of MyMixin as well as the method_x of
    > each respective Foo's second base class. One cannot simply call
    > FooN.method_x, because that will only call MyMixin.method_x and not
    > that of the other base.
    >
    > 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.


    Out of curiosity, did you try this and are reporting that it resulted
    in an AttributeError, or did you merely deduce that it would raise
    AttributeError based on your knowledge of Python's inheritance?

    I ask this rhetorically. I know that you didn't try it (or that you
    tried it and made a mistake) because if you had tried it (and not made
    a mistake) you would have seen that it works exactly as you want it
    to.


    Carl Banks
    Carl Banks, Sep 6, 2009
    #4
  5. Re: Multiple inheritance - How to call method_x in InheritedBaseBfrom method_x in InheritedBaseA?

    On Sat, Sep 5, 2009 at 8:41 PM, Carl Banks<> wrote:
    > Out of curiosity, did you try this and are reporting that it resulted
    > in an AttributeError, or did you merely deduce that it would raise
    > AttributeError based on your knowledge of Python's inheritance?
    >
    > I ask this rhetorically.  I know that you didn't try it (or that you
    > tried it and made a mistake) because if you had tried it (and not made
    > a mistake) you would have seen that it works exactly as you want it
    > to.
    >
    >
    > Carl Banks
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >


    This code causes an error:

    #!/usr/bin/python

    def main():
    foox = FooX()
    fooy = FooY()
    fooz = FooZ()

    #foox.method_x("I", "AM", "X")
    print
    fooy.method_x("ESTOY", "Y", "!")
    print
    fooz.method_x(100, 200, 300)


    class MyMixin(object):

    def method_x(self, a, b, c):
    super(MyMixin, self).method_x(a, b, c)
    print "MyMixin.method_x(%s, %s, %s, %s)" % (repr(self),
    repr(a), repr(b), repr(c))

    class BaseA(object):

    def method_x(self, a, b, c):
    super(BaseA, self).method_x(a, b, c)
    print "BaseA.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    repr(b), repr(c))

    class BaseB(object):

    pass

    class BaseC(object):

    def method_x(self, a, b, c):
    super(BaseC, self).method_x(a, b, c)
    print "BaseC.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    repr(b), repr(c))

    class FooX(BaseA, MyMixin):

    def method_x(self, a, b, c):
    super(FooX, self).method_x(a, b, c)
    print "FooX.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    repr(b), repr(c))

    class FooY(BaseB, MyMixin):

    pass

    class FooZ(BaseC, MyMixin):

    def method_x(self, a, b, c):
    super(FooZ, self).method_x(a, b, c)
    print "FooZ.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    repr(b), repr(c))

    if __name__ == '__main__':
    main()


    Traceback (most recent call last):
    File "foo.py", line 54, in <module>
    main()
    File "foo.py", line 10, in main
    fooy.method_x("ESTOY", "Y", "!")
    File "foo.py", line 18, in method_x
    super(MyMixin, self).method_x(a, b, c)
    AttributeError: 'super' object has no attribute 'method_x'
    The Music Guy, Sep 7, 2009
    #5
  6. Re: Multiple inheritance - How to call method_x in InheritedBaseBfrom method_x in InheritedBaseA?

    Sorry, that last code had a typo in it:

    #!/usr/bin/python

    def main():
    foox = FooX()
    fooy = FooY()
    fooz = FooZ()

    foox.method_x("I", "AM", "X")
    print
    fooy.method_x("ESTOY", "Y", "!")
    print
    fooz.method_x(100, 200, 300)


    class MyMixin(object):

    def method_x(self, a, b, c):
    super(MyMixin, self).method_x(a, b, c)
    print "MyMixin.method_x(%s, %s, %s, %s)" % (repr(self),
    repr(a), repr(b), repr(c))

    class BaseA(object):

    def method_x(self, a, b, c):
    super(BaseA, self).method_x(a, b, c)
    print "BaseA.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    repr(b), repr(c))

    class BaseB(object):

    pass

    class BaseC(object):

    def method_x(self, a, b, c):
    super(BaseC, self).method_x(a, b, c)
    print "BaseC.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    repr(b), repr(c))

    class FooX(BaseA, MyMixin):

    def method_x(self, a, b, c):
    super(FooX, self).method_x(a, b, c)
    print "FooX.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    repr(b), repr(c))

    class FooY(BaseB, MyMixin):

    pass

    class FooZ(BaseC, MyMixin):

    def method_x(self, a, b, c):
    super(FooZ, self).method_x(a, b, c)
    print "FooZ.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    repr(b), repr(c))

    if __name__ == '__main__':
    main()


    Traceback (most recent call last):
    File "foo.py", line 54, in <module>
    main()
    File "foo.py", line 8, in main
    foox.method_x("I", "AM", "X")
    File "foo.py", line 40, in method_x
    super(FooX, self).method_x(a, b, c)
    File "foo.py", line 24, in method_x
    super(BaseA, self).method_x(a, b, c)
    File "foo.py", line 18, in method_x
    super(MyMixin, self).method_x(a, b, c)
    AttributeError: 'super' object has no attribute 'method_x'
    The Music Guy, Sep 7, 2009
    #6
  7. The Music Guy

    Carl Banks Guest

    Re: Multiple inheritance - How to call method_x in InheritedBaseBfrom method_x in InheritedBaseA?

    On Sep 6, 10:48 pm, The Music Guy <> wrote:
    > Sorry, that last code had a typo in it:
    >
    > #!/usr/bin/python
    >
    > def main():
    >     foox = FooX()
    >     fooy = FooY()
    >     fooz = FooZ()
    >
    >     foox.method_x("I", "AM", "X")
    >     print
    >     fooy.method_x("ESTOY", "Y", "!")
    >     print
    >     fooz.method_x(100, 200, 300)
    >
    > class MyMixin(object):
    >
    >     def method_x(self, a, b, c):
    >         super(MyMixin, self).method_x(a, b, c)
    >         print "MyMixin.method_x(%s, %s, %s, %s)" % (repr(self),
    > repr(a), repr(b), repr(c))
    >
    > class BaseA(object):
    >
    >     def method_x(self, a, b, c):
    >         super(BaseA, self).method_x(a, b, c)
    >         print "BaseA.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    > repr(b), repr(c))
    >
    > class BaseB(object):
    >
    >     pass
    >
    > class BaseC(object):
    >
    >     def method_x(self, a, b, c):
    >         super(BaseC, self).method_x(a, b, c)
    >         print "BaseC.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    > repr(b), repr(c))
    >
    > class FooX(BaseA, MyMixin):
    >
    >     def method_x(self, a, b, c):
    >         super(FooX, self).method_x(a, b, c)
    >         print "FooX.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    > repr(b), repr(c))
    >
    > class FooY(BaseB, MyMixin):
    >
    >     pass
    >
    > class FooZ(BaseC, MyMixin):
    >
    >     def method_x(self, a, b, c):
    >         super(FooZ, self).method_x(a, b, c)
    >         print "FooZ.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    > repr(b), repr(c))
    >
    > if __name__ == '__main__':
    >     main()
    >
    > Traceback (most recent call last):
    >   File "foo.py", line 54, in <module>
    >     main()
    >   File "foo.py", line 8, in main
    >     foox.method_x("I", "AM", "X")
    >   File "foo.py", line 40, in method_x
    >     super(FooX, self).method_x(a, b, c)
    >   File "foo.py", line 24, in method_x
    >     super(BaseA, self).method_x(a, b, c)
    >   File "foo.py", line 18, in method_x
    >     super(MyMixin, self).method_x(a, b, c)
    > AttributeError: 'super' object has no attribute 'method_x'


    That's not what you did in your original post, though.

    Mixins should be listed first among bases, which is how you did it in
    your original post, and how it had to be in order for it to "just
    work" as I claimed.

    class FooX(MyMixin, BaseA)
    class FooY(MyMixin, BaseB)
    class FooZ(MyMixin, BaseC)



    If you are concerned that a base class might not define method_x (and
    therefore that the super call from MyMixin would fail), then there are
    a couple things you can do. First thing is to consider whether you
    ought to be using two method instead of one.

    Otherwise the easiest thing is to catch and ignore AttributeError from
    MyMixin's method_x:

    class MyMixin(object):
    def method_x(self, a, b, c):
    try:
    f = super(MyMixin, self).method_x
    except AttributeError:
    pass
    else:
    f(a,b,c)

    Note that you don't want to call the super inside the try block
    otherwise you risk catching spurrious AttributeErrors.

    This strategy might hide some typo-style errors with the base class,
    so if you're worried about that, another strategy would be to define
    another mixin which provides an empty method_x:

    class ProvideMethodX(self):
    def method_x(self, a, b, c):
    pass

    Then if BaseB does not define method_x, derive FooY from it like this:

    class FooY(MyMixin,ProvideMethodX,BaseB)

    Finally (and probably least confusingly) you could use separate mixins
    for bases that define method_x and those that don't.


    Carl Banks
    Carl Banks, Sep 7, 2009
    #7
  8. Re: Multiple inheritance - How to call method_x in InheritedBaseBfrom method_x in InheritedBaseA?

    On Mon, Sep 7, 2009 at 3:30 PM, Carl Banks<> wrote:
    >
    > That's not what you did in your original post, though.
    >
    > Mixins should be listed first among bases, which is how you did it in
    > your original post, and how it had to be in order for it to "just
    > work" as I claimed.
    >
    > class FooX(MyMixin, BaseA)
    > class FooY(MyMixin, BaseB)
    > class FooZ(MyMixin, BaseC)
    >
    >
    >
    > If you are concerned that a base class might not define method_x (and
    > therefore that the super call from MyMixin would fail), then there are
    > a couple things you can do.  First thing is to consider whether you
    > ought to be using two method instead of one.
    >
    > Otherwise the easiest thing is to catch and ignore AttributeError from
    > MyMixin's method_x:
    >
    > class MyMixin(object):
    >    def method_x(self, a, b, c):
    >        try:
    >            f = super(MyMixin, self).method_x
    >        except AttributeError:
    >            pass
    >        else:
    >            f(a,b,c)
    >
    > Note that you don't want to call the super inside the try block
    > otherwise you risk catching spurrious AttributeErrors.
    >
    > This strategy might hide some typo-style errors with the base class,
    > so if you're worried about that, another strategy would be to define
    > another mixin which provides an empty method_x:
    >
    > class ProvideMethodX(self):
    >    def method_x(self, a, b, c):
    >        pass
    >
    > Then if BaseB does not define method_x, derive FooY from it like this:
    >
    > class FooY(MyMixin,ProvideMethodX,BaseB)
    >
    > Finally (and probably least confusingly) you could use separate mixins
    > for bases that define method_x and those that don't.
    >
    >
    > Carl Banks
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >


    I was trying to adapt Ryles' code into my existing example. I did what
    I thought Ryles did, but it didn't seem to work. I also tried flipping
    the order of the parents, as you suggested, but that didn't seem to
    change anything; it gives the same error.

    Also, there is no fear that one of the bases will not define method_x.
    The current API *requires* that all bases (MyMixin, BaseA, etc.)
    define a method_x, so if it does not exist for a base class, the
    developer isn't following the instructions. ;)
    The Music Guy, Sep 9, 2009
    #8
  9. Re: Multiple inheritance - How to call method_x in InheritedBaseBfrom method_x in InheritedBaseA?

    I should also mention--and I should have realized this much
    sooner--that each of the BaseN classes are themselves each going to
    have at least one common base which will define method_x, so each
    BaseN will be calling that if it defines its own method_x. Again,
    sorry I didn't mention that sooner. For some reason it didn't occur to
    me that it would be important. I feel dumb now... :p

    Here is the updated current example:

    class CommonBase(object):
    def method_x(self, a, b c):
    ... no call to superclass' method_x is needed here ...

    class MyMixin(object):
    def method_x(self, a, b, c):
    get_other_base(self).method_x(self, a, b, c)
    ...

    class BaseA(CommonBase):
    def method_x(self, a, b, c):
    super(BaseA, self).method_x(a, b, c)
    ...

    class BaseB(CommonBaset):
    ...

    class BaseC(CommonBase):
    def method_x(self, a, b, c):
    super(BaseC, self).method_x(a, b, c)
    ...

    class FooX(MyMixin, BaseA):
    ...

    class FooY(MyMxin, BaseB):
    ...

    class FooZ(MyMixin, BaseC):
    ...
    The Music Guy, Sep 9, 2009
    #9
  10. The Music Guy

    ryles Guest

    Re: Multiple inheritance - How to call method_x in InheritedBaseBfrom method_x in InheritedBaseA?

    On Sep 9, 1:47 am, The Music Guy <> wrote:
    > I should also mention--and I should have realized this much
    > sooner--that each of the BaseN classes are themselves each going to
    > have at least one common base which will define method_x, so each
    > BaseN will be calling that if it defines its own method_x. Again,
    > sorry I didn't mention that sooner. For some reason it didn't occur to
    > me that it would be important. I feel dumb now... :p
    >
    > Here is the updated current example:
    >
    > class CommonBase(object):
    >     def method_x(self, a, b c):
    >         ... no call to superclass' method_x is needed here ...
    >
    > class MyMixin(object):
    >    def method_x(self, a, b, c):
    >        get_other_base(self).method_x(self, a, b, c)
    >        ...
    >
    > class BaseA(CommonBase):
    >    def method_x(self, a, b, c):
    >        super(BaseA, self).method_x(a, b, c)
    >        ...
    >
    > class BaseB(CommonBaset):
    >    ...
    >
    > class BaseC(CommonBase):
    >    def method_x(self, a, b, c):
    >        super(BaseC, self).method_x(a, b, c)
    >        ...
    >
    > class FooX(MyMixin, BaseA):
    >    ...
    >
    > class FooY(MyMxin, BaseB):
    >    ...
    >
    > class FooZ(MyMixin, BaseC):
    >    ...


    OK, how about this?

    class CommonBase(object):
    def method_x(self, a, b, c):
    print "CommonBase"

    class MyMixin(object):
    def method_x(self, a, b, c):
    print "MyMixin",
    super(MyMixin, self).method_x(a, b, c)

    class BaseA(CommonBase):
    def method_x(self, a, b, c):
    print "BaseA",
    super(BaseA, self).method_x(a, b, c)

    class BaseB(CommonBase):
    def method_x(self, a, b, c):
    print "BaseB",
    super(BaseB, self).method_x(a, b, c)

    class BaseC(CommonBase):
    def method_x(self, a, b, c):
    print "BaseC",
    super(BaseC, self).method_x(a, b, c)

    class FooX(MyMixin, BaseA):
    def method_x(self, a, b, c):
    print "FooX",
    super(FooX, self).method_x(a, b, c)

    class FooY(MyMixin, BaseB):
    def method_x(self, a, b, c):
    print "FooY",
    super(FooY, self).method_x(a, b, c)

    class FooZ(MyMixin, BaseC):
    # Supposing this class doesn't require a specialized method_x.
    pass


    FooX().method_x(1, 2, 3) # Prints 'FooX MyMixin BaseA CommonBase'
    FooY().method_x(1, 2, 3) # Prints 'FooY MyMixin BaseB CommonBase
    FooZ().method_x(1, 2, 3) # Prints 'MyMixin BaseC CommonBase'

    ---

    Each method_x implementation uses super() to ensure that the next base
    class method_x is called. The exception is CommonBase, which is
    presumed to be the hierarchy root.

    http://www.python.org/download/releases/2.2.3/descrintro/#cooperation
    http://www.python.org/download/releases/2.3/mro
    ryles, Sep 9, 2009
    #10
  11. The Music Guy

    Carl Banks Guest

    Re: Multiple inheritance - How to call method_x in InheritedBaseBfrom method_x in InheritedBaseA?

    On Sep 8, 10:47 pm, The Music Guy <> wrote:
    > I should also mention--and I should have realized this much
    > sooner--that each of the BaseN classes are themselves each going to
    > have at least one common base which will define method_x, so each
    > BaseN will be calling that if it defines its own method_x. Again,
    > sorry I didn't mention that sooner. For some reason it didn't occur to
    > me that it would be important. I feel dumb now... :p
    >
    > Here is the updated current example:
    >
    > class CommonBase(object):
    >     def method_x(self, a, b c):
    >         ... no call to superclass' method_x is needed here ...
    >
    > class MyMixin(object):
    >    def method_x(self, a, b, c):
    >        get_other_base(self).method_x(self, a, b, c)
    >        ...


    What is get_other_base? Just use a regular super call here,
    get_other_base and hacks like that are what gets you into trouble.

    You seem to be overthinking this. You don't need to. Just use super
    () in MyMixin, and in all the other classes, consistently, and mind
    the order of the bases.

    And if I were you I wouldn't keep making updates to a "current
    example" because first you do questionable things define a
    get_other_base method, then you try to apply my advice without
    reverting to the original form you posted. Well of course you're
    going to have issues if you do that. Instead, start from scratch, and
    try to get a small example working, using your orginial post and my
    original suggestion. Once that works then try to apply it to your
    working example.


    Carl Banks
    Carl Banks, Sep 9, 2009
    #11
  12. Re: Multiple inheritance - How to call method_x in InheritedBaseBfrom method_x in InheritedBaseA?

    On Wed, Sep 9, 2009 at 1:21 PM, Carl Banks<> wrote:
    > On Sep 8, 10:47 pm, The Music Guy <> wrote:


    > What is get_other_base?  Just use a regular super call here,
    > get_other_base and hacks like that are what gets you into trouble.
    >
    > You seem to be overthinking this.  You don't need to.  Just use super
    > () in MyMixin, and in all the other classes, consistently, and mind
    > the order of the bases.
    >
    > And if I were you I wouldn't keep making updates to a "current
    > example" because first you do questionable things define a
    > get_other_base method, then you try to apply my advice without
    > reverting to the original form you posted.  Well of course you're
    > going to have issues if you do that.  Instead, start from scratch, and
    > try to get a small example working, using your orginial post and my
    > original suggestion.  Once that works then try to apply it to your
    > working example.
    >


    get_other_base() is supposed to return the other superclass (base)
    that is being used in conjunction with the current superclass. So if
    FooX inherits from MyMixin and BaseB, and get_other_base(self) is
    called from a method defined in MyMixin, BaseB is returned. In any
    case, that function is merely psuedocode, not an actual part of the
    implementation. Its purpose in my example was merely to show the
    effect I was trying to acheive. I used it because I'm having trouble
    understanding exactly how the super() function works; it always seems
    to do something I didn't expect, or not do something that I did
    expect. (I say this after having read the online documentation, btw.)

    Anyway, Ryles' last suggestion helped a lot. Thanks, Ryles. (And Carl
    and Scott, too, of course.) Here's the code I'm going with:

    def main():

    basea = BaseA()
    baseb = BaseB()
    basec = BaseC()

    foox = FooX()
    fooy = FooY()
    fooz = FooZ()

    basea.method_x("I", "Am", "BaseA!");
    print
    baseb.method_x("One", "Two", "Three");
    print
    basec.method_x("Ay", "Bee", "See");
    print

    print

    foox.method_x("I", "AM", "X")
    print
    fooy.method_x("ESTOY", "Y", "!")
    print
    fooz.method_x(100, 200, 300)


    class MyMixin(object):

    def method_x(self, a, b, c):
    super(MyMixin, self).method_x(a, b, c)
    print "MyMixin.method_x(%s, %s, %s, %s)" % (repr(self),
    repr(a), repr(b), repr(c))

    class CommonBase(object):

    def method_x(self, a, b, c):
    print "CommonBase.method_x(%s, %s, %s, %s)" % (repr(self),
    repr(a), repr(b), repr(c))

    class BaseA(CommonBase):

    def method_x(self, a, b, c):
    super(BaseA, self).method_x(a, b, c)
    print "BaseA.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    repr(b), repr(c))

    class BaseB(CommonBase):

    def method_x(self, a, b, c):
    super(BaseB, self).method_x(a, b, c)
    print "BaseB.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    repr(b), repr(c))

    class BaseC(CommonBase):

    pass

    class FooX(MyMixin, BaseA):

    def method_x(self, a, b, c):
    super(FooX, self).method_x(a, b, c)
    print "FooX.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    repr(b), repr(c))

    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.method_x(%s, %s, %s, %s)" % (repr(self), repr(a),
    repr(b), repr(c))

    if __name__ == '__main__':
    main()


    Output:


    CommonBase.method_x(<__main__.BaseA object at 0xb7d0d42c>, 'I', 'Am', 'BaseA!')
    BaseA.method_x(<__main__.BaseA object at 0xb7d0d42c>, 'I', 'Am', 'BaseA!')

    CommonBase.method_x(<__main__.BaseB object at 0xb7d0d44c>, 'One',
    'Two', 'Three')
    BaseB.method_x(<__main__.BaseB object at 0xb7d0d44c>, 'One', 'Two', 'Three')

    CommonBase.method_x(<__main__.BaseC object at 0xb7d0d46c>, 'Ay', 'Bee', 'See')


    CommonBase.method_x(<__main__.FooX object at 0xb7d0d48c>, 'I', 'AM', 'X')
    BaseA.method_x(<__main__.FooX object at 0xb7d0d48c>, 'I', 'AM', 'X')
    MyMixin.method_x(<__main__.FooX object at 0xb7d0d48c>, 'I', 'AM', 'X')
    FooX.method_x(<__main__.FooX object at 0xb7d0d48c>, 'I', 'AM', 'X')

    CommonBase.method_x(<__main__.FooY object at 0xb7d0d4ac>, 'ESTOY', 'Y', '!')
    BaseB.method_x(<__main__.FooY object at 0xb7d0d4ac>, 'ESTOY', 'Y', '!')
    MyMixin.method_x(<__main__.FooY object at 0xb7d0d4ac>, 'ESTOY', 'Y', '!')

    CommonBase.method_x(<__main__.FooZ object at 0xb7d0d4cc>, 100, 200, 300)
    MyMixin.method_x(<__main__.FooZ object at 0xb7d0d4cc>, 100, 200, 300)
    FooZ.method_x(<__main__.FooZ object at 0xb7d0d4cc>, 100, 200, 300)


    You may notice that MyMixin calls the super's method before doing
    anything of its own. This is intentional--MyMixin's job cannot be done
    correctly until the other bases have done their part.
    The Music Guy, Sep 10, 2009
    #12
  13. Re: Multiple inheritance - How to call method_x in InheritedBaseBfrom method_x in InheritedBaseA?

    Btw, Carl, please forgive me if I frustrate you, because I'm trying my
    best not to. I'm trying to keep track of what I did and what you did
    and what Ryles and Scott did, while at the same time trying to keep a
    firm grasp of exactly what it is I'm trying to acheive. Besides that,
    I'm not a professional programmer--just a hobbyist. And of course,
    there's all the other IRL things I'm trying to deal with
    simultaneously with this...hopefully you can see how I would make
    mistakes.
    The Music Guy, Sep 10, 2009
    #13
  14. The Music Guy

    Carl Banks Guest

    Re: Multiple inheritance - How to call method_x in InheritedBaseBfrom method_x in InheritedBaseA?

    On Sep 9, 4:37 pm, The Music Guy <> wrote:
    > On Wed, Sep 9, 2009 at 1:21 PM, Carl Banks<> wrote:
    > > On Sep 8, 10:47 pm, The Music Guy <> wrote:
    > > What is get_other_base?  Just use a regular super call here,
    > > get_other_base and hacks like that are what gets you into trouble.

    >
    > > You seem to be overthinking this.  You don't need to.  Just use super
    > > () in MyMixin, and in all the other classes, consistently, and mind
    > > the order of the bases.

    >
    > > And if I were you I wouldn't keep making updates to a "current
    > > example" because first you do questionable things define a
    > > get_other_base method, then you try to apply my advice without
    > > reverting to the original form you posted.  Well of course you're
    > > going to have issues if you do that.  Instead, start from scratch, and
    > > try to get a small example working, using your orginial post and my
    > > original suggestion.  Once that works then try to apply it to your
    > > working example.

    >
    > get_other_base() is supposed to return the other superclass (base)
    > that is being used in conjunction with the current superclass. So if
    > FooX inherits from MyMixin and BaseB, and get_other_base(self) is
    > called from a method defined in MyMixin, BaseB is returned. In any
    > case, that function is merely psuedocode, not an actual part of the
    > implementation.


    Ah, but see unless you tell us that, we will not know and will give
    you inappropriate advice. Moral of the story: post the code that you
    actually ran. And if you take anyone's advice, apply it to the actual
    code they were advising you on.


    > Its purpose in my example was merely to show the
    > effect I was trying to acheive. I used it because I'm having trouble
    > understanding exactly how the super() function works; it always seems
    > to do something I didn't expect, or not do something that I did
    > expect. (I say this after having read the online documentation, btw.)


    super() is unfortunately misnamed after the analogous feature of Java;
    the analogy breaks down under multiple inheritance. Think of super as
    more like "call next method", where the next method could be from a
    base class or a sister class. However it always works left to right
    in the list of bases, which is why it was important for MyMixin to be
    listed first.


    > Anyway, Ryles' last suggestion helped a lot. Thanks, Ryles. (And Carl
    > and Scott, too, of course.) Here's the code I'm going with:


    I'm glad it worked out.


    Carl Banks
    Carl Banks, Sep 10, 2009
    #14
  15. The Music Guy

    ryles Guest

    Re: Multiple inheritance - How to call method_x in InheritedBaseBfrom method_x in InheritedBaseA?

    On Sep 9, 7:48 pm, The Music Guy <> wrote:
    > Btw, Carl, please forgive me if I frustrate you, because I'm trying my
    > best not to. I'm trying to keep track of what I did and what you did
    > and what Ryles and Scott did, while at the same time trying to keep a
    > firm grasp of exactly what it is I'm trying to acheive. Besides that,
    > I'm not a professional programmer--just a hobbyist. And of course,
    > there's all the other IRL things I'm trying to deal with
    > simultaneously with this...hopefully you can see how I would make
    > mistakes.


    Glad to see your project is afoot. Multiple inheritance is tricky
    stuff. Try to keep class hierarchies simple and prefer composition
    when feasible.

    Have a look at the links I suggested in my previous post, particularly
    the new-style classes paper. It's tough reading but if you get through
    it you'll gain a lot.

    And don't worry about Carl, he's a Calvin Klein model and, as you
    know, sometimes they can get a bit moody ;)
    ryles, Sep 10, 2009
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. maxw_cc
    Replies:
    1
    Views:
    3,108
    Martijn van Steenbergen
    Dec 21, 2003
  2. cppsks
    Replies:
    0
    Views:
    797
    cppsks
    Oct 27, 2004
  3. karthikbalaguru
    Replies:
    9
    Views:
    1,019
  4. Daniel Pitts
    Replies:
    27
    Views:
    1,863
    Mike Schilling
    Feb 27, 2008
  5. Rouslan Korneychuk
    Replies:
    8
    Views:
    568
    Rouslan Korneychuk
    Feb 10, 2011
Loading...

Share This Page