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

Carl Banks pavlovevidence at gmail.com
Mon Sep 7 16:30:51 EDT 2009


On Sep 6, 10:48 pm, The Music Guy <music... at alphaios.net> 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



More information about the Python-list mailing list