Как в Python создать простой метакласс

«Как в Python создать простой метакласс» — вопрос из категории ООП, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Метакласс в Python — это "класс для классов". Если обычный класс определяет, как создаются и ведут себя объекты (экземпляры), то метакласс определяет, как создаются и ведут себя сами классы.

По умолчанию метаклассом для всех классов является type. Чтобы создать свой, нужно унаследовать класс от type и переопределить его метод __new__ или __init__.

Пример: Метакласс, добавляющий атрибут created_at ко всем классам

import time

# 1. Создаем метакласс, наследуясь от type
class TimestampMeta(type):
    # 2. Переопределяем __new__
    # Этот метод вызывается при создании нового КЛАССА
    def __new__(cls, name, bases, namespace):
        # Добавляем новый атрибут в пространство имен будущего класса
        namespace['created_at'] = time.ctime()
        print(f"Создание класса '{name}' с метаклассом TimestampMeta...")

        # Вызываем __new__ родительского класса (type) для завершения создания
        return super().__new__(cls, name, bases, namespace)

# 3. Применяем метакласс к нашему классу
class MyModel(metaclass=TimestampMeta):
    def __init__(self):
        self.data = "some data"

# Проверяем, что атрибут был добавлен в класс
print(MyModel.created_at)
# > Создание класса 'MyModel' с метаклассом TimestampMeta...
# > [текущее время, например, 'Mon Dec 18 15:30:00 2023']

Разбор метода __new__:

  • cls: Сам метакласс (TimestampMeta).
  • name: Имя создаваемого класса в виде строки ('MyModel').
  • bases: Кортеж родительских классов ((object,)).
  • namespace: Словарь, содержащий все атрибуты и методы, определенные в теле класса ({'__init__': <function...>, '__module__': ...}). Мы можем изменять этот словарь перед созданием класса.

Основные сценарии использования:

  • Автоматическая регистрация: Регистрация плагинов или моделей в реестре (как в Django ORM).
  • Валидация: Проверка, что создаваемый класс соответствует определенным правилам (например, имеет нужные методы).
  • Инъекция атрибутов: Автоматическое добавление логгеров, полей или методов в классы.