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

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

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

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

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

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


person Simon Tewsi    schedule 13.08.2013    source источник


Ответы (2)


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

Если вы передадите 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() следующим, с чего мы и начали.

person Martijn Pieters    schedule 13.08.2013
comment
Отлично, очень ясно, объяснение, спасибо. - person Simon Tewsi; 13.08.2013

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

person Ignacio Vazquez-Abrams    schedule 13.08.2013