Mixin в Python: что такое классы-миксины?

В этом уроке вы узнаете о классах-миксинах в Python и о том, как их использовать для повторного использования кода.

Содержание

Что такое миксин в Python?

Миксин (mixin)— это класс в Python, который предоставляет реализации методов для повторного использования несколькими связанными дочерними классами.

Миксин не определяет новый тип. Поэтому он не предназначен для реализации направления. Он объединяет набор методов для повторного использования. Каждый миксин должен иметь одно конкретное поведение, реализующее тесно связанные методы. Обычно дочерний класс использует множественное наследование для объединения классов-миксинов с родительским классом.

Поскольку Python не определяет формальный способ определения классов-миксинов, рекомендуется в названии класса добавлять суффикс Mixin. Класс-миксин в Python схож на интерфейс в Java и C# с реализацией. И это похоже на особенность PHP.

Пример класса-миксина в Python

Сначала определите класс Person:

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

Затем определите класс Employee, который наследуется от класса Person:

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

В-третьих, создайте новый экземпляр класса Employee:

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

Предположим, вы хотите преобразовать объект «Employee» в словарь. Для этого вы можете добавить в класс «Employee» новый метод, который преобразует объект в словарь.

Однако вы можете захотеть преобразовать объекты других классов в словари. Чтобы сделать код повторно используемым, вы можете определить класс-миксин под названием DictMixin следующим образом:

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 value

Класс DictMixin имеет метод to_dict(), который преобразует объект в словарь. Метод _traverse_dict() перебирает атрибуты объекта и присваивает результату ключ и значение.

Атрибут объекта может быть списком, словарем или объектом с атрибутом __dict__. Поэтому метод _traverse_dict() использует метод _traverse() для преобразования атрибута в значение.

Чтобы преобразовать экземпляры класса Employee в словари, Employee необходимо наследовать классы DictMixin и Person:

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

Обратите внимание, что вам необходимо указать классы-миксины перед другими классами.

Следующий пример создает новый экземпляр класса Employee и преобразует его в словарь:

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

pprint(e.to_dict())

Выход:

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

Ниже показан полный код:

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())

Составление нескольких классов-миксинов

Предположим, вы хотите преобразовать объект «Employee» в JSON. Для этого вы можете сначала определить новый класс-миксин, использующий стандартный модуль json:

import json

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

А затем измените класс Employee, чтобы он наследовал класс JSONMixin:

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

Следующий пример создает новый экземпляр класса Employee и преобразует его в словарь и 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())

Выход:

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

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

Ниже показан полный код:

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())
Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *