Skip to content

Metaclass

Метакласи

Метакласи [🔥36/100]

Summary

Метаклас - клас, який створює класи і визначає поведінку класів. Вони дозволяють контролювати процес створення класу, модифікувати його атрибути, методи та поведінку.

Метакласи працюють шляхом перехоплення створення класу на момент його визначення. При визначенні класу інтерпретатор Python шукає метаклас у його базових класах і, якщо знаходить, використовує його для створення нового класу.

Один з основних способів використання метакласів полягає в реалізації паттерну проектування "Одинак" (Singleton), де метаклас може гарантувати, що від класу може бути створений лише один екземпляр. Метакласи також використовуються в фреймворках, таких як Django і SQLAlchemy, для створення моделей бази даних.

У Python 3 метаклас задається ключовим аргументом metaclass= у заголовку класу (class MyClass(metaclass=Registry): ...). Атрибут __metaclass__ - застарілий механізм Python 2; у Python 3 він ігнорується.

Створення класу з автоматичною реєстрацією у системі

class Registry(type):
    def __init__(cls, name, bases, attrs):
        super().__init__(name, bases, attrs)
        register(cls)

class MyClass(metaclass=Registry):
    pass

Links

Що таке type. Як працює пошук метакласу при створенні об'єкта [💡13/100]

Три прояви type

  • метаклас всіх класів. А самі класи можна вважати розширенням простих об'єктів
  • type(a) - повертає тип об'єкту
  • type(name, bases, attrs) - виклик конструктора класу

type - це метаклас, який Python внутрішньо використовує для створення всіх класів. Отже, при замовчування, батьком буде object, а метакласом - type.

При написанні коду

class Foo(Bar):
    pass

Python визначає метаклас так (Python 3):

  • якщо у заголовку класу явно вказано metaclass=... - береться він;
  • інакше метаклас визначається як найпохідніший (most derived) серед метакласів усіх базових класів (type(Bar) і т.д.);
  • якщо базових класів немає і метаклас не вказано - використовується type.

Механізм із атрибутом __metaclass__ (у класі чи на рівні модуля) належить Python 2 і в Python 3 не діє - тут його наведено лише для історичного контексту.

Навіщо використовувати метакласи [💡24/100]

Основне застосування метакласів - це створення фреймфорків. Типовий приклад - Django ORM.

class Person(models.Model):
  name = models.CharField(max_length=30)
  age = models.IntegerField()

guy = Person(name='bob', age='35')
print(guy.age)

age - не IntegerField, а int, при цьому значення може бути отримано прямо з бази даних.

Це можливо, оскільки models.Model визначає __metaclass__, який здійснює деяку магію і перетворює клас Person, який визначений простим виразом, на складне зв'язування з базою даних.

Django робить щось складне, що виглядає простим, надаючи просте API та використовуючи метакласи, які відтворюють код з API і непомітно виконують усю роботу.

Межі застосування. Метакласи - рідкісний інструмент: у переважній більшості задач їх замінюють простішими механізмами - __init_subclass__ для логіки при створенні підкласів, __set_name__ і дескриптори для поведінки атрибутів, декоратори класів або делегування. Класична настанова Тіма Пітерса: "Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't." Потреба в метакласах у прикладному (а не фреймворковому) коді частіше є сигналом про проблему в архітектурі, ніж про реальну потребу.