Метакласс и атрибуты: кто получает created?
@python_quizРазберем этот квиз
Коротко: код использует метакласс, который переопределяет __call__. При создании экземпляра метакласс добавляет атрибут created именно в объект-экземпляр, поэтому вывод будет: False True.
Ниже подробно разберём, почему так происходит, и покажем альтернативы.
Исходный код

Запуск этого кода выводит:

Пошаговое объяснение
- Определён метакласс M, который наследует от type и переопределяет метод
__call__. - В вызове B() интерпретатор вызывает M.
__call__(B, ...). То есть__call__метакласса отвечает за создание экземпляра класса B. - Внутри M.
__call__сначала вызывается super().__call__(*a, **k). Это стандартное поведение — создание экземпляра (выделение памяти и вызов A.__init__). - После создания экземпляра код устанавливает obj.
created = True— атрибут устанавливается в самом экземпляре. - Возвращается экземпляр obj. Следовательно:
- hasattr(b, 'created') — True (атрибут есть в экземпляре).
- hasattr(B, 'created') — False (атрибут не установлен на самом классе B).
То есть метакласс управляет процессом создания экземпляров, но в данном коде модификация направлена на объект, а не на класс.
Анализ вариантов ответов (логика)
- "True True": произошло бы, если бы и класс, и экземпляр имели атрибут created. В текущем коде атрибут ставится только у экземпляра, потому этот вариант неверен.
- "False True": соответствует описанному поведению: класс не получает created, экземпляр получает — это именно наблюдаемый вывод.
- "True False": означало бы, что created добавлен к классу, но не к экземпляру. При установке attr на класс (например, cls.
created = True) такой результат возможен, но не в данном коде. - "False False": означало бы, что ни класс, ни экземпляр не получили created — не соответствует действительности, потому что экземпляр явно получает атрибут.
Варианты изменения поведения
- Сделать так, чтобы атрибут был у класса:

Обратите внимание: после установки cls.created = True класс B будет иметь created, и hasattr(b, 'created') тоже вернёт True, потому что при поиске атрибутов Python смотрит в __dict__ экземпляра, затем в классе.
- Установить атрибут во время создания класса (в метаклассе
__new__или__init__метакласса):

Это способ влиять на сами классы при их определении, а не при создании их экземпляров.
Короткий вывод
Переопределение __call__ в метаклассе даёт точку управления при создании экземпляров. В приведённом коде метакласс добавляет атрибут к самому экземпляру, а не к классу, поэтому hasattr(B, 'created') возвращает False, а hasattr(b, 'created') — True. Этот паттерн полезен, когда нужно инициализировать или пометить экземпляры централизованно при их создании.