在派生类中调用super()时,我可以传入self .__ class__吗?

这个问题已经在这里有了答案:

  • 如何避免使用super()进行无限递归?                                     1个答案

我最近发现(通过StackOverflow)在我应该调用的基类中调用方法:

self.__class__

很好,可以。 但是,我发现自己在进行更改时经常在类之间进行复制和粘贴,而经常忘记将派生的类参数固定为super()函数。

我想避免必须记住要更改派生类参数。 我可以改用self.__class__作为super()函数的第一个参数吗?

它似乎可行,但是有充分的理由为什么我不应该这样做?

Simon Tewsi asked 2020-02-23T02:42:31Z
2个解决方案
79 votes

你不能。 Subclass调用需要知道该方法属于哪个类,才能在基类中搜索被覆盖的方法。

如果您输入了Subclass(或者更佳的是[Subclass, Derived, Base]),则会为super()提供错误的起点来搜索方法,最终将再次调用其自己的方法。

在构成方法解析顺序序列的类列表中,将其视为指针。 如果传入Subclass,则指针将引用任何子类,而不是原始起点。

以下代码导致无限递归错误:

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[Subclass, Derived, Base],而不是super()

在该示例中,用于Subclass的MRO是[Subclass, Derived, Base],并且super()需要知道从哪里开始搜索任何覆盖的方法。 通过使用type(self),您告诉它从Subclass开始,因此接下来将找到Derived.method(),这就是我们开始的地方。

Martijn Pieters answered 2020-02-23T02:43:13Z
12 votes

self.__class__可能不是子类,而是子孙类,从而导致堆栈中断循环。

Ignacio Vazquez-Abrams answered 2020-02-23T02:43:33Z
translate from https://stackoverflow.com:/questions/18208683/when-calling-super-in-a-derived-class-can-i-pass-in-self-class