Метакласс, namespace и наследование в Python

Метакласс, namespace и наследование в Python

@python_quiz

Разберем этот квиз

Коротко: у нас есть метакласс, который в своём __new__ добавляет атрибут x в пространство имён создаваемого класса. Одновременно у нас есть базовый класс Base с собственным x. Вопрос — какие значения будут у Base.x и Child.x, и будет ли экземпляр Child считаться экземпляром Base.

Условие (код)

python

Как это работает — по шагам

  1. type('Base', (), {'x': 1}) создаёт класс Base обычным способом (метакласс — type). У класса Base в атрибутах хранится x = 1.
  2. При создании Child вызывается метакласс Meta:

- Python формирует namespace (ns) для нового класса. В данном случае ns — пустой словарь, потому что {} передали при создании.
- Вызывается Meta.__new__(mcls, name, bases, ns). Внутри __new__ код добавляет ns['x'] = 10 — то есть атрибут x добавляется в namespace будущего класса Child.
- Затем super().__new__ создаёт сам объект класса Child, используя уже дополненный словарь ns.

  1. В результате:

- Base.x остаётся 1, потому что мы не меняли класс Base.
- Child.x равно 10 — атрибут определён прямо в классе Child.
- Child наследует от Base, поэтому isinstance(Child(), Base) возвращает True (наследование сохраняется).

Выполнение и вывод

Если запустить приведённый код, он выведет:

text

Пояснения:

  • Первый элемент — Base.x = 1.
  • Второй — Child.x = 10.
  • Третий — True, потому что Child является подклассом Base, и экземпляр Child — экземпляр Base.

Разбор вариантов (почему другие ответы не подходят)

  • "1 10 False" — неверно, потому что хотя значения x у Base и Child установлены как 1 и 10, экземпляр Child всё же является экземпляром Base из-за наследования.
  • "10 10 True" — неверно, потому что Base.x не изменялся метаклассом при создании Child; Base.x остался 1.
  • "10 1 True" — неверно, потому что Child.x получил значение 10 в своём классовом namespace, а Base.x был 1.

Выводы и полезные наблюдения

  • Метакласс получает namespace каждого создаваемого класса отдельно. Изменения делаются в namespace конкретного класса, а не в его базах.
  • Использование метакласса позволяет программно добавлять или менять атрибуты классов при их создании.
  • Наследование классов и поведение isinstance зависят от иерархии классов (bases), а не от того, какие атрибуты добавлены метаклассом.

Если нужно, можно расширить пример: показать, как метакласс может модифицировать bases, добавить методы, или как отличить действия в __new__ и __init__ метакласса.

Report Page