Ответ
Метакласс в 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).
- Валидация: Проверка, что создаваемый класс соответствует определенным правилам (например, имеет нужные методы).
- Инъекция атрибутов: Автоматическое добавление логгеров, полей или методов в классы.
Ответ 18+ 🔞
А, метаклассы в Python, ёпта! Ну это ж как высший пилотаж, блядь. Сейчас объясню на пальцах, только не обосрись со смеху.
Представь, обычный класс — это как чертёж для табуретки. По нему штампуешь табуретки-объекты. А метакласс — это, сука, чертёж для самих чертежей! То есть инструкция, как создавать эти самые чертежи-классы. Во какие завороты, блядь!
По дефолту у всех классов метакласс — это type, старый добрый тип. Но если хочешь творить магию на уровне создания классов, нужно наследоваться от type и переопределить методы.
Вот тебе пример: метакласс, который автоматом прикручивает время создания к каждому классу
import time
# 1. Делаем метакласс, наследуясь от type
class TimestampMeta(type):
# 2. Переопределяем __new__ — это главный колдунский метод
# Он вызывается, когда создаётся новый КЛАСС, а не объект!
def __new__(cls, name, bases, namespace):
# Подсовываем в пространство имён будущего класса новый атрибут
namespace['created_at'] = time.ctime()
print(f"Вот я создаю класс '{name}' через метакласс TimestampMeta, бля...")
# А теперь пусть родительский type довершит дело
return super().__new__(cls, name, bases, namespace)
# 3. Применяем эту хуйню к своему классу
class MyModel(metaclass=TimestampMeta):
def __init__(self):
self.data = "какие-то данные"
# Смотри, что получилось!
print(MyModel.created_at)
# > Вот я создаю класс 'MyModel' через метакласс TimestampMeta, бля...
# > [тут будет время, типа 'Mon Dec 18 15:30:00 2023']
Что за параметры в __new__, блядь:
cls: Это сам метакласс, нашTimestampMeta.name: Имя класса, который создаём, в виде строки. Будет'MyModel'.bases: Кортеж из родительских классов. Обычно(object,).namespace: Словарь, куда сложено всё, что написали в теле класса — методы, атрибуты. Его можно, сука, как хочешь допиливать перед тем, как класс родится!
А где это, блядь, применяется? Да везде, где нужно колдовать над самими классами, а не их экземплярами!
- Авторегистрация всякой хуйни: Как в Django ORM — написал класс модели, а он сам в реестр записался.
- Проверки, что класс правильный: Чтобы, например, все нужные методы были на месте, а то пиздец.
- Автоматическое добавление полей или методов: Подкинуть всем классам логгер, таймстамп или ещё какую-нибудь обязаловку.
В общем, мощнейшая штука, но если бездумно применять — можно так наколдовать, что потом сам не разберёшься, в рот меня чих-пых!