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