Python Mixins

Matt mattj.morrison at gmail.com
Thu Sep 22 23:14:39 CEST 2011


I'm curious about what people's opinions are about using mixins in
Python. I really like, for example, the way that class based views
were implemented in Django 1.3 using mixins. It makes everything
extremely customizable and reusable. I think this is a very good
practice to follow, however, in Python mixins are achieved by using
(or perhaps misusing) inheritance and often multiple inheritance.

Inheritance is a very powerful tool, and multiple inheritance is an
even more powerful tool. These tools have their uses, but I feel like
"mixing in" functionality is not one of them. There are much different
reasons and uses for inheriting functionality from a parent and mixing
in functionality from elsewhere.

As a person, you learn certain things from your parents, you learn
other things from your peers all of those things put together becomes
you. Your peers are not your parents, that would not be possible. You
have completely different DNA and come from a completely different
place.

In terms of code, lets say we have the following classes:

class Animal
class Yamlafiable
class Cat(Animal, Yamlafiable)
class Dog(Animal, Yamlafiable)

I've got an Animal that does animal things, a Cat that does cat things
and a Dog that does dog things. I've also got a Yamlafiable class that
does something clever to generically convert an object into Yaml in
some way. Looking at these classes I can see that a Cat is an Animal,
a Dog is an Animal, a Dog is not a Cat, a Cat is not a Dog, a Dog is a
Yamlafiable? and a Cat is a Yamlafiable? Is that really true? If my
objects are categorized correctly, in the correct inheritance
hierarchy shouldn't that make more sense? Cats and Dogs aren't
Yamlafiable, that doesn't define what they are, rather it defines
something that they can do because of things that they picked up from
their friend the Yamlafile.

This is just a ridiculous example, but I think it is valid to say that
these things shouldn't be limited to inherit functionality only from
their parents, that they can pick other things up along the way as
well. Which is easy to do, right?

Dog.something_new = something_new

(I wish my stupid dog would learn that easily)

Ideally, what I would like to see is something like Ruby's mixins. It
seems to me like Ruby developed this out of necessity due to the fact
that it does not support multiple inheritance, however I think the
implementation is much more pure than inheriting from things that
aren't your parents. (although having only a single parent doesn't
make much sense either, I believe there are very few actual documented
cases of that happening). Here is a Ruby snippet:

module ReusableStuff
    def one_thing
        "something cool"
    end
end
class MyClass < MyParent
    include ReusableStuff
end

x = MyClass.new
x.one_thing == "something cool"
MyClass.superclass == Object

So I'm inheriting from MyParent and mixing in additional functionality
from ReusableStuff without affecting who my Parents are. This, to me,
makes much more sense than using inheritance to just grab a piece of
functionality that I want to reuse. I wrote a class decorator for
Python that does something similar (https://gist.github.com/1233738)
here is a snippet from that:

class MyMixin(object):
    def one_thing(self):
        return "something cool"

@mixin(MyMixin)
class MyClass(object):
    pass

x = MyClass()
x.one_thing() == 'something cool'
x.__class__.__bases__ ==  (object,)

To me, this is much more concise. By looking at this I can tell what
MyClass IS, who it's parents are and what else it can do. I'm very
interested to know if there are others who feel as dirty as I do when
using inheritance for mixins or if there are other things that Python
developers are doing to mix in functionality without using inheritance
or if the general populous of the Python community disagrees with me
and thinks that this is a perfectly valid use of inheritance.

I look forward to hearing back.

Thanks,
Matthew J Morrison
www.mattjmorrison.com


P.S. - This is a good article about not using inheritance as a code
reuse tool: http://littletutorials.com/2008/06/23/inheritance-not-for-code-reuse/



More information about the Python-list mailing list