Python: Вызов super().__init__() в метаклассах

Я столкнулся с проблемой: я не очень понимаю, зачем нужно вызывать super().__init() в метаклассе. Так как, по определению метакласс это фабрика классов, зачем нужно вызывать конструктор экземпляра (Ведь в init мы даже не передаем имя класса, а просто аргументы)? Ведь это не очень логично. Мой IDE говорит, что я должен написать этот вызов, но без него все работает. Не могли ли бы Вы, помочь мне? Заранее спасибо! (Мой код ниже, вызов конструктора init закомментирован.)

from collections import OrderedDict
class Descriptor:
    _counter = 0

    def __init__(self):
        self.attr_name = f'{Descriptor._counter}'
        Descriptor._counter += 1

    def __get__(self, instance, owner):
        return self if instance is None else instance.__dict__[self.attr_name]

    def __set__(self, instance, value):
        if value > 0:
            instance.__dict__[self.attr_name] = value
        else:
            msg = 'Value must be > 0!'
            raise AttributeError(msg)


class Meta(type):
    def __init__(cls, name, bases, attr_dict):
        #super().__init__(name, bases, attr_dict) <-
        for key, value in attr_dict.items():
            if isinstance(value, Descriptor):
                value.attr_name = key

    @classmethod
    def __prepare__(metacls, name, bases):
        return OrderedDict()


class Shop(metaclass=Meta):
    weight = Descriptor()
    price = Descriptor()

    def __init__(self, name, price, weight):
        self.name = name
        self.price = price
        self.weight = weight

    def __repr__(self):
        return f'{self.name}: price - {self.price} weight - {self.weight}'

    def buy(self):
        return self.price * self.weight

Ответы (1 шт):

Автор решения: Roman Konoval

С точки зрения питона, Meta это в первую очередь класс. А это значит, что когда вызывается его конструктор и создается экземпляр класса, то нужно вызвать конструктор предка, чтобы предок сделал необходимую инициализацию.

Именно поэтому IDE показывает, что здесь вызов нужен.

Другое дело, что type.__init__ очевидно делает что-то не слишком существенное (вообще или для сценария который тестируете), поэтому, даже если вызов пропустить, то работает. Не нужно забывать, что часть логики создания еще есть и в __new__. Если и его переопределить и не вызвать __new__ у предка, то тогда все, что делает type, а именно создание собственно класса, сломается.

В общем случае предком вашего класса может быть любой другой класс и его __init__ может содержать очень существенную инициализацию и ее пропускать нельзя. Хорошим тоном является вызов __init__ у предка, даже если он (сейчас) ничего не делает. Это делает код лучше поддерживаемым. Представьте, что вы переходите на новую версию питона, а там type.__init__ стал делать что-то важное - класс сломается.

То что класс Meta дополнительно используется еще как и метакласс класса Shop никак с этим не связанно.

→ Ссылка