Python supports multiple inheritance, while it doesn’t provide the syntax for interface. See PEP-0245. Of course, you can use the abc module for abstract base classes, which seems tricky.

Python introduces a concept called mixin that encapsulates behavior that can be reused in other classes. It’s supported via multiple inheritance, the difference of inheritance and mixin is, inheritance means “is-a” and mixin means “has-a”.

This post will illustrate how mixin works with a simple example.

Assume we have a class named Animal and its subclasses Dog and Chicken.

class Animal:
    pass

class Dog(Animal):
    pass

class Chicken(Animal):
    pass

These classes make no sense since they have no any method. Let’s add a method representing whether this animal eat meat or not.

class Animal:
    pass

class Dog(Animal):
    def eatMeat():
        return True 

class Chicken(Animal):
    def eatMeat():
        return False

It seems follows the rules of OOD, but how about more subclass, such as Cat and Goose.

class Cat(Animal):
    def eatMeat():
        return True 

class Goose(Animal):
    def eatMeat():
        return False

It appears a code smell. The first idea that comes your mind is improve the inheritance.

class EatMeatAnimal(Animal):
    def eatMeat():
        return True 

class NoMeatAnimal(Animal):
    def eatMeat():
        return False

class Dog(EatMeatAnimal): pass
class Chicken(NoMeatAnimal): pass
class Cat(EatMeatAnimal): pass
class Goose(NoMeatAnimal): pass

Next, if we want to implement another method hasWings, we have to append more classes.

class HasWingsEatMeatAnimal(EatMeatAnimal):
    def hasWings():
        return True

class HasWingsNoMeatAnimal(NoMeatAnimal):
    def hasWings():
        return True

class NoWingsEatMeatAnimal(EatMeatAnimal):
    def hasWings():
        return False

class NoWingsNoMeatAnimal(NoMeatAnimal):
    def hasWings():
        return False

That’s not enough, we must modify our concrete classes too.

class Dog(NoWingsEatMeatAnimal): pass
class Cat(NoWingsEatMeatAnimal): pass
class Chicken(HasWingsNoMeatAnimal): pass
class Goose(HasWingsNoMeatAnimal): pass

I know few people has the patience to read the above dummy code. Let’s see a pythonic way.

class Animal:
    pass

class EatMeatMixin:
    def eatMeat():
        return True 

class NoMeatMixin:
    def eatMeat():
        return False

class HasWingsMixin:
    def hasWings():
        return True

class NoWingsMixin:
    def hasWings():
        return False

class Dog(EatMeatMixin, NoWingsMixin, Animal): pass
class Cat(EatMeatMixin, NoWingsMixin, Animal): pass
class Chicken(NoMeatMixin, HasWingsMixin, Animal): pass
class Goose(NoMeatMixin, HasWingsMixin, Animal): pass

That’s mixin attaching behaviors for the main class Animal.

Actually, mixin is not an advanced feature of Python, but ubiquitous. For example, the built-in socketserver.py implements a server model based on process or thread with mixin, and this post pave the way for me to analyze the code in the future.

Reference