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/ -- http://mail.python.org/mailman/listinfo/python-list