[python] What is a mixin, and why are they useful?

This answer aims to explain mixins with examples that are:

  • self-contained: short, with no need to know any libraries to understand the example.

  • in Python, not in other languages.

    It is understandable that there were examples from other languages such as Ruby since the term is much more common in those languages, but this is a Python thread.

It shall also consider the controversial question:

Is multiple inheritance necessary or not to characterize a mixin?

Definitions

I have yet to see a citation from an "authoritative" source clearly saying what is a mixin in Python.

I have seen 2 possible definitions of a mixin (if they are to be considered as different from other similar concepts such as abstract base classes), and people don't entirely agree on which one is correct.

The consensus may vary between different languages.

Definition 1: no multiple inheritance

A mixin is a class such that some method of the class uses a method which is not defined in the class.

Therefore the class is not meant to be instantiated, but rather serve as a base class. Otherwise the instance would have methods that cannot be called without raising an exception.

A constraint which some sources add is that the class may not contain data, only methods, but I don't see why this is necessary. In practice however, many useful mixins don't have any data, and base classes without data are simpler to use.

A classic example is the implementation of all comparison operators from only <= and ==:

class ComparableMixin(object):
    """This class has methods which use `<=` and `==`,
    but this class does NOT implement those methods."""
    def __ne__(self, other):
        return not (self == other)
    def __lt__(self, other):
        return self <= other and (self != other)
    def __gt__(self, other):
        return not self <= other
    def __ge__(self, other):
        return self == other or self > other

class Integer(ComparableMixin):
    def __init__(self, i):
        self.i = i
    def __le__(self, other):
        return self.i <= other.i
    def __eq__(self, other):
        return self.i == other.i

assert Integer(0) <  Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) >  Integer(0)
assert Integer(1) >= Integer(1)

# It is possible to instantiate a mixin:
o = ComparableMixin()
# but one of its methods raise an exception:
#o != o 

This particular example could have been achieved via the functools.total_ordering() decorator, but the game here was to reinvent the wheel:

import functools

@functools.total_ordering
class Integer(object):
    def __init__(self, i):
        self.i = i
    def __le__(self, other):
        return self.i <= other.i
    def __eq__(self, other):
        return self.i == other.i

assert Integer(0) < Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) > Integer(0)
assert Integer(1) >= Integer(1)

Definition 2: multiple inheritance

A mixin is a design pattern in which some method of a base class uses a method it does not define, and that method is meant to be implemented by another base class, not by the derived like in Definition 1.

The term mixin class refers to base classes which are intended to be used in that design pattern (TODO those that use the method, or those that implement it?)

It is not easy to decide if a given class is a mixin or not: the method could be just implemented on the derived class, in which case we're back to Definition 1. You have to consider the author's intentions.

This pattern is interesting because it is possible to recombine functionalities with different choices of base classes:

class HasMethod1(object):
    def method(self):
        return 1

class HasMethod2(object):
    def method(self):
        return 2

class UsesMethod10(object):
    def usesMethod(self):
        return self.method() + 10

class UsesMethod20(object):
    def usesMethod(self):
        return self.method() + 20

class C1_10(HasMethod1, UsesMethod10): pass
class C1_20(HasMethod1, UsesMethod20): pass
class C2_10(HasMethod2, UsesMethod10): pass
class C2_20(HasMethod2, UsesMethod20): pass

assert C1_10().usesMethod() == 11
assert C1_20().usesMethod() == 21
assert C2_10().usesMethod() == 12
assert C2_20().usesMethod() == 22

# Nothing prevents implementing the method
# on the base class like in Definition 1:

class C3_10(UsesMethod10):
    def method(self):
        return 3

assert C3_10().usesMethod() == 13

Authoritative Python occurrences

At the official documentatiton for collections.abc the documentation explicitly uses the term Mixin Methods.

It states that if a class:

  • implements __next__
  • inherits from a single class Iterator

then the class gets an __iter__ mixin method for free.

Therefore at least on this point of the documentation, mixin does not not require multiple inheritance, and is coherent with Definition 1.

The documentation could of course be contradictory at different points, and other important Python libraries might be using the other definition in their documentation.

This page also uses the term Set mixin, which clearly suggests that classes like Set and Iterator can be called Mixin classes.

In other languages

  • Ruby: Clearly does not require multiple inheritance for mixin, as mentioned in major reference books such as Programming Ruby and The Ruby programming Language

  • C++: A virtual method that is set =0 is a pure virtual method.

    Definition 1 coincides with the definition of an abstract class (a class that has a pure virtual method). That class cannot be instantiated.

    Definition 2 is possible with virtual inheritance: Multiple Inheritance from two derived classes

Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to oop

How to implement a simple scenario the OO way When to use 'raise NotImplementedError'? PHP: cannot declare class because the name is already in use Python class input argument Call an overridden method from super class in typescript Typescript: How to extend two classes? What's the difference between abstraction and encapsulation? An object reference is required to access a non-static member Java Multiple Inheritance Why not inherit from List<T>?

Examples related to multiple-inheritance

Java Multiple Inheritance Can a normal Class implement multiple interfaces? Can an interface extend multiple interfaces in Java? Class extending more than one class Java? Can one class extend two classes? Multiple inheritance for an anonymous class How does Python's super() work with multiple inheritance? Does C# support multiple inheritance? What is a mixin, and why are they useful? What does 'super' do in Python?

Examples related to mixins

Sass - Converting Hex to RGBa for background opacity Syntax for if/else condition in SCSS mixin What is a mixin, and why are they useful?