[Tutor] 'Right' way to implement mixins in Python?

chombee chombee at nerdshack.com
Wed May 28 22:41:36 CEST 2008


I'm writing an event-driven GUI framework. I have several independent
units of functionality such as Draggable, Highlightable, etc. Although
these units of functionality are independent of each other, they do all
depend on a certain base implementation that they work with. I want
widget objects to be able to select different combinations of these
capabilities at will. So mixins seemed like the way to go.

It seemed to me that the most natural way to implement mixins in Python
is to use multiple inheritance with new-style classes. But I certainly
confused myself a lot trying to do it. I think I have come up with the
solution, although its late and this is pretty rushed, but I thought it
would put it out there for comment. Is this the right thing to do?

The lessons I learned are that, when implementing mixins using multiple
inheritance:

* Mixin classes should not derive from any base class (except object)
* But they may assume that the classes they will be mixed in with do
derive from a certain base class, so they may assume the base class is
there.

Here's some code showing the approach that seems to work for me:

<code>

class Base(object):
    """Base class for mixer classes. All mixin classes
    require the classes they are mixed in with to be
    instances of this class (or a subclass)."""
    
    def __init__(self,b):
        self.b = b # Mixin classes assume this attribute will be present
        
class MixinBPlusOne(object):
    """A mixin class that implements the print_b_plus_one
    method."""

    def __init__(self):
        print 'MixinBPlusOne initialising'

    def print_b_plus_one(self):
        print self.b+1

class MixinBMinusOne(object):
    """A mixin class that implements the print_b_minus_one
    method."""

    def __init__(self):
        print 'MixinBMinusOne initialising'

    def print_b_minus_one(self):
        print self.b-1
       
class Mixer(Base,MixinBPlusOne,MixinBMinusOne):
    """A mixer class (class that inherits some mixins), this
    will work because it also inherits Base, which the
    mixins expect."""

    def __init__(self,b):
        # I feel like I should be using super here because 
        # I'm using new-style classes and multiple
        # inheritance, but the argument list of
        # Base.__init__ differs from those of the Mixin
        # classes, and this seems to work anyway.
        Base.__init__(self,b)
        MixinBPlusOne.__init__(self)
        MixinBMinusOne.__init__(self)
        
class BrokenMixer(MixinBPlusOne,MixinBMinusOne):
    """This will not work because it does not inherit Base,
    which the mixins expect it to do."""

    pass
    
m = Mixer(9)
m.print_b_plus_one()
m.print_b_minus_one()

m = BrokenMixer(9)
m.print_b_plus_one() # It'll crash here.

</code>

It outputs this, the result I expected:

MixinBPlusOne initialising
MixinBMinusOne initialising
10
8
<crash!>




More information about the Tutor mailing list