Python Mixins

Thomas Jollans t at jollybox.de
Thu Sep 22 18:09:08 EDT 2011


On 2011-09-22 23:14, Matt wrote:
> 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 think this is an excellent use of multiple inheritance. One could also
have a construction like this:

class Dog (Animal)
class YamlafialbleDog (Dog, Yamlafiable)

... which you may be more comfortable with. In you above example, yes, a
Dog object is a Yamlafiable object. If you need a Yamlafiable object,
you can use a Cat or Dog. That's what inheritance is about.

In Python or Ruby, this way of doing things is not all that different
from the one you present below. Here, it doesn't really matter. In
strictly typed languages, it makes a world of difference. What if you
don't care what kind of object you're dealing with, as long as it
supports the interface a certain mixin provides? In Python, true, duck
typing will do the trick. In C++, for example, where you could use the C
preprocessor to do something like Ruby mixins, multiple inheritance is a
lot more useful for mixing in something that has a public interface.

The Vala language, and, I suppose the GObject type system, actually
allows interfaces to act as mixins. This is really a more formalised way
of doing just this: using multiple inheritance (which, beyond
interfaces, Vala does not support) to mix in functionality.

Oh and your thing looks kind of neat.

Thomas

> 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