При вызове super() в производном классе могу ли я передать self.__class__?

Я недавно обнаружил (через Stackru), что для вызова метода в базовом классе я должен вызвать:

super([[derived class]], self).[[base class method]]()

Это нормально, это работает. Тем не менее, я часто копирую и вставляю между классами, когда делаю изменения, и часто забываю зафиксировать аргумент производного класса в функции super().

Я хотел бы избежать необходимости помнить об изменении аргумента производного класса. Могу ли я вместо этого просто использовать self.__class__ как первый аргумент функции super()?

Кажется, это работает, но есть ли веские причины, почему я не должен этого делать?

2 ответа

Решение

Нет, ты не можешь. super() call должен знать, к какому классу относится метод, для поиска в базовых классах переопределенного метода.

Если вы проходите в self.__class__ (или еще лучше, type(self)) затем super() ему дается неправильная начальная точка для поиска методов, и он снова вызовет свой собственный метод.

Рассматривайте его как указатель в списке классов, которые формируют последовательность порядка разрешения методов. Если вы проходите в type(self) тогда указатель будет ссылаться на любые подклассы вместо исходной начальной точки.

Следующий код приводит к бесконечной ошибке рекурсии:

class Base(object):
    def method(self):
        print 'original'

class Derived(Base):
    def method(self):
        print 'derived'
        super(type(self), self).method()

class Subclass(Derived):
    def method(self):
        print 'subclass of derived'
        super(Subclass, self).method()

Демо-версия:

>>> Subclass().method()
subclass of derived
derived
derived
derived

<... *many* lines removed ...>

  File "<stdin>", line 4, in method
  File "<stdin>", line 4, in method
  File "<stdin>", line 4, in method
RuntimeError: maximum recursion depth exceeded while calling a Python object

так как type(self) является Subclassне Derived, в Derived.method(),

В примере MRO для Subclass является [Subclass, Derived, Base], а также super() Нужно знать, с чего начать поиск любых переопределенных методов. Используя type(self) вы говорите, чтобы начать с Subclassтак что найдешь Derived.method() следующий, с которого мы и начали.

self.__class__ может быть не подкласс, а класс внука или младшего, что приводит к циклу разрушения стека.

Другие вопросы по тегам