Hunting the Shmoo

Screencasts and blog posts on workflow, productivity, tools, Mozilla and whatever else tickles my fancy.

When would you use a Python mixin?

That’s not a rhetorical question. I’d like to know in which scenarios a mixin in python really is the best option. I can’t seem to think of any, but maybe I’m not thinking outside the box enough.

The basic idea of a mixin is to create a small re-usable class that can “plug-in” to other larger classes. From the wikipedia definition, a mixin is a way to compose classes together without using inheritance. The problem is unlike ruby, python mixins are a purely conceptual construct. Python mixins are inheritance (the only difference is that the class name usually contains ‘Mixin’). It is up to the developer to remember this, and to manually avoid all of the common pitfalls of multiple inheritance. This kind of defeats the whole purpose of the mixin in the first place. What’s more is that most people use python mixins improperly.

Consider the following example:

from book import Book
from index import IndexMixin

class TextBook(Book, IndexMixin):
    def __init__(self, name, contents, edition='1st'):
        Book.__init__(self, name, contents)
        self.edition = edition

t = TextBook('Learn Python the Hard Way')
t.search('python')
>>> 0 results found

Here we correctly use inheritance to denote Book as a base class, a textbook is a book. We use an IndexMixin because textbooks aren’t indices, they have an index. We then instantiate it and search the book for the string ‘python’. Wait a minute, how can a textbook about python not contain the word python? In python, the multiple inheritance chain is read right to left, this means that IndexMixin is technically the base class here. It just so happens that IndexMixin also has a function called search which overrides the one defined in Book.

It turns out there’s another way to compose classes together without using inheritance. Just use the class (or module) directly:

from book import Book
from index import Index

class TextBook(Book):
    def __init__(self, name, contents, edition='1st'):    
        Book.__init__(self, name, contents)
        self.edition = edition
        self.index = Index()

t = TextBook('Learn Python the Hard Way')
t.search('python')
>>> Many results found

t.index.search('python')
>>> 0 results found

If the relationship between objects A and B is “A is a B”, then B is a base class, not a mixin. If the relationship is “A has a B”, then why not use composition? What benefit does a mixin give you?


Share

Comments

Screwtape
24/05/2014

A good example of mixins in Python would be the "collections.abc" module in the standard library. For example, if you implement __getitem__() and __len__() then inherit from collections.abc.Sequence, you automatically get implementations of __contains__(), __iter__(), __reversed__(), index() and count() methods. If you used composition, you would have to manually define each of those methods to call the equivalent method on your internal Sequence object, which is certainly possible but also pretty tedious.

Jj
24/05/2014

Depends on your need, not always coding is a perfect abstraction of reality. Classes and objects don't always represent real world entities with real world relationships.

I've found myself using mixins to extend funcionality, to provide base classes. I use Django a lot and using Forms, Views, Admin classes, mixins are a great tool to have. When having a set of related views, if you know the methods you can just write your own and a few helpers and save yourself a lot of coding just by defining classes that inherit from framework provided classes and your mixins, declare a couple of class attributes as configuration and be good to go.

William Lachance
24/05/2014

Yes, I think it just comes down to the fact that sometimes mixins are an easier way to get the behaviour that you want when expressing concepts that can't simply be defined as "A is a B" or "A has a B". Screwtape's example is good, another one that comes to mind in our code is the droid mixin we use in mozdevice for adding Android-specific functionality to DeviceManager:

http://mxr.mozilla.org/mozi...

For each implementation (ADB and SUT) we want a base class without the functionality, so a mixin is the best way of generating a new classes with the desired methods.

You are right about the gotchas though. In general I have found inheritance to not always work how I expect in Python and that includes Mixins. I guess that's the price you pay for its expressiveness vs. (e.g.) Java.

ahal
24/05/2014

Yeah, that is a good example, never really occurred to me.

ahal
24/05/2014

"If you know the methods" is the catch there in my opinion. You might know the methods, but someone else reading your code doesn't. I guess if you are working on something you know no one else will ever have to maintain it, then it doesn't really matter.

ahal
24/05/2014

Personally I think self.fennec.launch() is easier to understand than self.launch_fennec() in that case. But I guess that does show that it comes down to personal preference. The example you linked is really clear, but I've seen what happens when mixins get abused. And yes, it is possible to abuse composition as well :)

William Lachance
24/05/2014

I don't think your alternative implementation really makes sense. What would the fennec object represent? All we're doing is providing an interface to the Android "launch" mechanism, which properly belongs in the devicemanager class.

Jj
25/05/2014

That's a different point point. The case is that for those situations Mixins can be pretty helpful. Yes I didn't know the methods, but I read the docs and then I knew them. It's learning an interface just like any other library, you have to learn how to use it. It's not like methods in code are secrets.

ahal
26/05/2014

Definitely :). Good documentation goes a long way, but unfortunately good documentation is often a luxury. With composition it is easy to see which attributes come from which class by reading the code, there is no ambiguity. It is also easy for a small number of mixins. But when a class has 3+ mixins, it becomes a real pain to hunt down which attributes belong to which mixins.

Dejan Lekic
12/05/2015

I only recently started programming in Python (I am mostly C/C++/D/Java/BASH programmer)

It is hard to talk about mixins in a language which supports multiple-inheritance. I use mixins in D a lot. D (http://dlang.org) has two types of mixins. One is exactly the same as in Python, and in D parlance they are called "template mixins" (http://dlang.org/template-m..., and the other type are extremely powerful string mixins (http://dlang.org/mixin.html) which allows programmer to generate valid D code at compile-time.

Sure Python mixins are not 100% the same thing as D template mixins, but they are very very similar. And I find them extremely useful in cases when you want to add specific behaviour to any class.

Say for an example you want to be able to easily add a method called toJSON() which returns a JSON representation of the object's state. You can write a mixin which will use reflection to get members, and nicely generate JSON for you. You can then use this mixin in every class.

holdenweb
14/10/2016

But using composition you can use an instance of an object that uses reflection to get members, and call _its_ toJSON() method. This also allows you to use dependency injection, making it easier to test the code using a mock object and to use different types of object to implement toJSON(). This more flexible approach loosens coupling and makes designs more readily adaptable.

Leave a comment

Your comment has been submitted and will be published once it has been approved.