Pregunta

Consider two classes that each have an existing shared function, but separate inheritance paths:

class ClazzA(SuperClazzX):
    def foo(self):
        return goo(super(SuperClazzX, self).foo())

class ClazzB(SuperClazzY):
    def foo(self):
        return goo(super(SuperClazzY, self).foo())

foo is clearly a common function which can be extracted to a mixin, what is the right way to do so, such that the functionality remains even though a different super foo is to be called?

Edit: I removed the other mixin, it was confusing and irrelevant.

¿Fue útil?

Solución

EDIT: simpler code

Mixin has access to other bases of (future) child class, here C::Mixin::foo has access to the other base of C, namely C::Base::foo. Authoritative explanation here.

class Base(object):  # must be new-style class in py 2.x
    def foo(self):
        print "base foo called"

class Mixin(object):
    def foo(self):
        rv = super(Mixin, self).foo()  # call actual implementation
        # use rv

class C(Mixin, Base):
    pass

C().foo()
base foo called

What this does:

  • self is instance of C, it's __mro__ is (Mixin, Base)
  • when Mixin calls super(Mixin, self), the resulting object retains bases (Base,)
  • when .foo attribute is resolved, this object finds it in Base
  • thus Base.foo is invoked with original self

If you want custom control over implementation, you have access to your own bases, e.g.:

class Foo(...):
    def foo(self):
        print self.__class__.__bases__

Your mixin could look something like this, super-manual approach:

class Mixin(object):
    def foo(self):
        assert self.__class__ is not Mixin  # no point calling directly
        # find the other base
        other = [b for b in self.__class__.__bases__ if b is not Mixin]
        # what to do if there's more than 1 real base?
        # pick base explicitly
        base = other[1]
        # call it, 
        return something(base.foo(self, some_args))
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top