магический метод __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 шт):

Автор решения: Pak Uula

Эм... Вам не нужно ничего делать в 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'
→ Ссылка