Python mixin

Summary: in this tutorial, you’ll learn about Python mixin classes and how to use them to make the code reusable.

What is a mixin in Python

A mixin is a class that provides method implementations for reuse by multiple related child classes. However, the inheritance is not implying an is-a relationship.

A mixin doesn’t define a new type. Therefore, it is not intended for direction instantiation.

A mixin bundles a set of methods for reuse. Each mixin should have a single specific behavior, implementing closely related methods.

Typically, a child class uses multiple inheritance to combine the mixin classes with a parent class.

Since Python doesn’t define a formal way to define mixin classes, it’s a good practice to name mixin classes with the suffix Mixin.

A mixin class is like an interface in Java and C# with implementation. And it’s like a trait in PHP.

Python Mixin example

First, define a Person class:

class Person:
    def __init__(self, name):
        self.name = nameCode language: Python (python)

Second, define an Employee class that inherits from the Person class:

class Employee(Person):
    def __init__(self, name, skills, dependents):
        super().__init__(name)
        self.skills = skills
        self.dependents = dependentsCode language: Python (python)

Third, create a new instance of the Employee class:

if __name__ == '__main__':
    e = Employee(
        name='John',
        skills=['Python Programming''Project Management'],
        dependents={'wife': 'Jane', 'children': ['Alice', 'Bob']}
    )Code language: Python (python)

Suppose you want to convert the Employee object to a dictionary. To do that, you can add a new method to the Employee class, which converts the object to a dictionary.

However, you may want to convert objects of other classes to dictionaries. To make the code reusable, you can define a mixin class called DictMixin like the following:

class DictMixin:
    def to_dict(self):
        return self._traverse_dict(self.__dict__)

    def _traverse_dict(self, attributes: dict) -> dict:
        result = {}
        for key, value in attributes.items():
            result[key] = self._traverse(key, value)

        return result

    def _traverse(self, key, value):
        if isinstance(value, DictMixin):
            return value.to_dict()
        elif isinstance(value, dict):
            return self._traverse_dict(value)
        elif isinstance(value, list):
            return [self._traverse(key, v) for v in value]
        elif hasattr(value, '__dict__'):
            return self._traverse_dict(value.__dict__)
        else:
            return valueCode language: Python (python)

The DictMixin class has the to_dict() method that converts an object to a dictionary.

The _traverse_dict() method iterates the object’s attributes and assigns the key and value to the result.

The attribute of an object may be a list, a dictionary, or an object with the __dict__ attribute. Therefore, the _traverse_dict() method uses the _traverse() method to convert the attribute to value.

To convert instances of the Employee class to dictionaries, the Employee needs to inherit from both DictMixin and Person classes:

class Employee(DictMixin, Person):
    def __init__(self, name, skills, dependents):
        super().__init__(name)
        self.skills = skills
        self.dependents = dependentsCode language: Python (python)

Note that you need to specify the mixin classes before other classes.

The following creates a new instance of the Employee class and converts it to a dictionary:

e = Employee(
    name='John',
    skills=['Python Programming', 'Project Management'],
    dependents={'wife': 'Jane', 'children': ['Alice', 'Bob']}
)

pprint(e.to_dict())Code language: Python (python)

Output:

{'dependents': {'children': ['Alice', 'Bob'], 'wife': 'Jane'},
'name': 'John',
'skills': ['Python Programming', 'Project Management']}Code language: Python (python)

The following shows the complete code:

from pprint import pprint


class DictMixin:
    def to_dict(self):
        return self._traverse_dict(self.__dict__)

    def _traverse_dict(self, attributes):
        result = {}
        for key, value in attributes.items():
            result[key] = self._traverse(key, value)

        return result

    def _traverse(self, key, value):
        if isinstance(value, DictMixin):
            return value.to_dict()
        elif isinstance(value, dict):
            return self._traverse_dict(value)
        elif isinstance(value, list):
            return [self._traverse(key, v) for v in value]
        elif hasattr(value, '__dict__'):
            return self._traverse_dict(value.__dict__)
        else:
            return value


class Person:
    def __init__(self, name):
        self.name = name


class Employee(DictMixin, Person):
    def __init__(self, name, skills, dependents):
        super().__init__(name)
        self.skills = skills
        self.dependents = dependents


if __name__ == '__main__':
    e = Employee(
        name='John',
        skills=['Python Programming', 'Project Management'],
        dependents={'wife': 'Jane', 'children': ['Alice', 'Bob']}
    )

    pprint(e.to_dict())Code language: Python (python)

Compose multiple mixin classes

Suppose you want to convert the Employee‘s object to JSON. To do that, you can first define a new mixin class that use the json standard module:

import json

class JSONMixin:
    def to_json(self):
        return json.dumps(self.to_dict())Code language: Python (python)

And then change the Employee class so that it inherits the JSONMixin class:

class Employee(DictMixin, JSONMixin, Person):
    def __init__(self, name, skills, dependents):
        super().__init__(name)
        self.skills = skills
        self.dependents = dependentsCode language: Python (python)

The following creates a new instance of the Employee class and converts it to a dictionary and json:

if __name__ == '__main__':
    e = Employee(
        name='John',
        skills=['Python Programming''Project Management'],
        dependents={'wife': 'Jane', 'children': ['Alice', 'Bob']}
    )

    pprint(e.to_dict())
    print(e.to_json())Code language: Python (python)

Output:

{'dependents': {'children': ['Alice', 'Bob'], 'wife': 'Jane'},
'name': 'John',
'skills': ['Python ProgrammingProject Management']}

{"name": "John", "skills": ["Python ProgrammingProject Management"], "dependents": {"wife": "Jane", "children": ["Alice", "Bob"]}}Code language: Python (python)

The following shows the complete code:

import json
from pprint import pprint


class DictMixin:
    def to_dict(self):
        return self._traverse_dict(self.__dict__)

    def _traverse_dict(self, attributes):
        result = {}
        for key, value in attributes.items():
            result[key] = self._traverse(key, value)

        return result

    def _traverse(self, key, value):
        if isinstance(value, DictMixin):
            return value.to_dict()
        elif isinstance(value, dict):
            return self._traverse_dict(value)
        elif isinstance(value, list):
            return [self._traverse(key, v) for v in value]
        elif hasattr(value, '__dict__'):
            return self._traverse_dict(value.__dict__)
        else:
            return value


class JSONMixin:
    def to_json(self):
        return json.dumps(self.to_dict())


class Person:
    def __init__(self, name):
        self.name = name


class Employee(DictMixin, JSONMixin, Person):
    def __init__(self, name, skills, dependents):
        super().__init__(name)
        self.skills = skills
        self.dependents = dependents


if __name__ == '__main__':
    e = Employee(
        name='John',
        skills=['Python Programming''Project Management'],
        dependents={'wife': 'Jane', 'children': ['Alice', 'Bob']}
    )

    pprint(e.to_dict())
    print(e.to_json())Code language: Python (python)

Summary

  • A mixin class provides method implementions for resuse by multiple related subclasses.
Did you find this tutorial helpful ?