Help us understand the problem. What is going on with this article?

EP 26 Use Multiple Inheritance Only for Mix-in Utility Classes

More than 3 years have passed since last update.
  • Avoid using multiple inheritance if mix-in classes can achieve the same outcome.
  • Use pluggable behaviors at the instance level to provide per-class customization when mix-in classes may require it.
  • Compose mix-ins to create complex functionality from simeple behaviors.

Effective Python

Mix-in

Mix-in is a small class that only define a set of additional methods that a class should provide.

In object-oriented programming languages, a mixin is a class that contains methods for use by other classes without having to be the parent class of those other classes. How those other classes gain access to the mixin's methods depends on the language. Mixins are sometimes described as being "included" rather than "inherited".

Mixins encourage code reuse and can be used to avoid the inheritance ambiguity that multiple inheritance can cause 1, or to work around lack of support for multiple inheritance in a language. A mixin can also be viewed as an interface with implemented methods. This pattern is an example of enforcing the dependency inversion principle.

https://en.wikipedia.org/wiki/Mixin

What is a mixin, and why are they useful?

http://stackoverflow.com/questions/533631/what-is-a-mixin-and-why-are-they-useful

A mixin is a special kind of multiple inheritance. There are two main situations where mixins are used:

You want to provide a lot of optional features for a class.
You want to use one particular feature in a lot of different classes.

import time

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

    def _traverse_dict(self, instance_dict):
        output = {}
        for key, value in instance_dict.items():
            output[key] = self._traverse(key, value)
        return output

    def _traverse(self, key, value):
        time.sleep(0.2)
        if isinstance(value, ToDictMixin):
            print('ToDictMixin')
            return value.to_dict()
        elif isinstance(value, dict):
            print('dict')
            return self._traverse_dict(value)
        elif isinstance(value, list):
            print('list')
            return [self._traverse(key, i) for i in value]
        elif hasattr(value, '__dict__'):
            print('hasattr __dict__')
            return self._traverse_dict(value.__dict__)
        else:
            return value

class BinaryTree(ToDictMixin):
    def __init__(self, value, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right

tree = BinaryTree(10, left=BinaryTree(7, right=BinaryTree(9)),
        right=BinaryTree(13, left=BinaryTree(11)))

# print(tree.to_dict())

Without overiding _traverse, BinaryTreeWithParent causes stack overflow by infinite loop.

to_dict -> _traverse_dict -> _traverse(isinstance of ToDictMixin) -> to_dict -> _travese_dict -> _traverse(isinstance of ToDitctMixin)...

class BinaryTreeWithParent(BinaryTree):
    def __init__(self, value, left=None, right=None, parent=None):
        super().__init__(value, left=left, right=right)
        self.parent = parent

    def _traverse(self, key, value):
        if (isinstance(value, BinaryTreeWithParent) and key == 'parent'):
            return value.value
        else:
            return super()._traverse(key, value)

root = BinaryTreeWithParent(10)
root.left = BinaryTreeWithParent(7, parent=root)
root.left.right = BinaryTreeWithParent(9, parent=root.left)
print(root.to_dict())

NamedSubTree also inherits ToDictMixin. However _travese behavior of BinaryTreeWithParent is not changed due to the polymorphism.

class NamedSubTree(ToDictMixin):
    def __init__(self, name, tree_with_parent):
        self.name = name
        self.tree_with_parent = tree_with_parent

my_tree = NamedSubTree('foobar', root)
print(my_tree.to_dict())


Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした