При вызове 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__
может быть не подкласс, а класс внука или младшего, что приводит к циклу разрушения стека.