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