Это фактически связано с обсуждением здесь на SO.
Краткая версия
def meta(name, bases, class_dict)
return type(name, bases, class_dict)
class Klass(object):
__metaclass__ = meta
meta() вызывается при выполнении Klass объявления класса.
Какая часть внутреннего кода (python internal) на самом деле вызывает meta()?
Длинная версия
Когда класс объявлен, некоторый код должен выполнить соответствующие проверки атрибутов и посмотреть, есть ли __metaclass__, объявленный в типе. Если такой существует, он должен выполнить вызов метода в этом метаклассе с хорошо известными атрибутами (class_name, bases, class_dict). Мне не совсем понятно, какой код отвечает за этот вызов.
Я сделал некоторое копание в CPython (см. ниже), но мне очень хотелось бы иметь что-то ближе к определенному ответу.
Вариант 1: Вызывается напрямую
Метаклассовый вызов жестко связан с разбором классов. Если да, есть ли какие-либо доказательства для этого?
Вариант 2: он вызывается type.__new__()
Код в type_call() вызывает type_new(), который в свою очередь вызывает _PyType_CalculateMetaclass(). Это говорит о том, что разрешение метакласса действительно выполняется во время вызова type() при попытке выяснить, какое значение нужно вернуть из type()
Это будет соответствовать понятию, что "класс" является "вызываемым, возвращающим объект".
Вариант 3: Что-то другое
Все мои догадки могут быть совершенно неправильными, конечно.
Некоторые примеры, с которыми мы столкнулись в чате:
Пример 1:
class Meta(type):
pass
class A:
__metaclass__ = Meta
A.__class__ == Meta
Это то, что возвращает Meta.__new__(), поэтому это кажется законным. Метакласс ставит себя как A.__class__
Пример 2:
class Meta(type):
def __new__(cls, class_name, bases, class_dict):
return type(class_name, bases, class_dict)
class A(object):
__metaclass__ = Meta
A.__class__ == type
Изменить 2: исправить исходную версию, правильно вывести Meta из type.
Кажется, все в порядке, но я не уверен, что это делает то, что я думаю. Также: Каков канонический метод, чтобы заставить его вести себя, как в примере 1?
Редактирование 3: Использование type.__new__(...) похоже на работу, как ожидалось, что также кажется в пользу варианта 2.
Может ли кто-нибудь с более глубоким знанием внутренней магии питона просветить меня?
Изменить: A для довольно кратких праймеров на метаклассах: http://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/. Также есть некоторые действительно красивые диаграммы, ссылки, а также подчеркивает различия между python 2 и 3.
Изменить 3: для Python 3 есть хороший ответ. Python 3 использует __build_class__ для создания объекта класса. Путь к коду - все равно - другой в Python 2.