магический метод __new__ ABCMeta python
Увидел метод __new__ для мета класса ABCMeta и пытаюсь понять какие аргументы нужно передать при вызове метода.
def __new__(mcls, name, bases, namespace, /, **kwargs):
cls = super().__new__(mcls, name, bases, namespace, **kwargs)
_abc_init(cls)
return cls
В качестве примера, я создам abc и с помощью __new__ должен создать экземпляр подкласса. Как я понял, __new__ вызывает метод __init__ для инициализации экземпляра подкласса.
Примерный код:
class A(metaclass=abc.ABCMeta):
@abstractmethod
def func(self):
raise NotImplementedError
class B:
def func(self):
print("inheritance")
class C:
pass
Теперь мы можем зарегистрировать производный класс B от A, с помощью register:
A.register(B)
Вместо того, чтобы создавать экземпляр как обычно:
`obj = B()`
Как я понимаю, мы можем вызвать метод __new__:
A.__new__(...)
Вопрос возникает на данном этапе, что я должен передать в качестве аргументов для метода __new__, исходя из исходного кода этого метода сверху?
Ответы (1 шт):
Эм... Вам не нужно ничего делать в A.__new__. Этот хук вызывается, когда вы создаёте новый объект типа A() или типов-наследников.
Тип B не является наследником типа A. Благодаря механике, реализованной в ABCMeta класс B признаётся как производный от A, но тип A не числится в списке классов-предков B, поэтому при создании объектов B() A.__new__ не вызывается.
Вызов A.__new__(A) создаст новый неициализированный объект типа A. Метод __new__ вызывается до __init__. Собственно, этот метод должен аллоцировать память для того самого self, который параметр в A.__init__(self).
В подавляющем большинстве классов метод __new__ не задан. Для таких классов вызвается object.__init__, который аллоцирует память под объект и присвает этому объекту ссылку на класс. Затем конструктор из оного класса заполняет новосозданный объект полями.
__new__ метаклассов
Но в случае метаклассов __new__ работает иначе. Когда вы создаёте новый класс A, кто-то должен создать объект тип А. Если у типа A нет метакласса, то вызывается метод type.__new__('A', list-of-base-classes-of-A, map-of-members-of-A). Этот метод аллоцирует память под тип A, наполняет его методами и статическими полями, заполняет данные, которые используются для поиска предков.
Но если у класса A есть метакласс SomeMeta, то при создании типового объекта для класса A вместо type.__new__ вызывается SomeMeta.__new__. Этот метод, по хорошему, тоже должен вызвать type.__new__ для инциализации A, чтобы потом заняться своими делами. Например, ABCMeta.__new__ пробегается по методам создаваемого класса и заполняет словарик A.__abstractmethods__ (с учётом наследования). Этот словарик изучает метод object.__new__ при создании объекта A() - если словарик не пуст, выбрасывается исключение
TypeError: Can't instantiate abstract class A without an implementation for abstract method 'func'