关于python:当在派生类中调用super()时,我可以传入self.__class__吗?

When calling super() in a derived class, can I pass in self.__class__?

本问题已经有最佳答案,请猛点这里访问。

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

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

很好,它起作用了。但是,当我进行更改时,我发现自己经常在类之间复制和粘贴,并且经常忘记将派生类参数固定到super()函数。

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

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


不,你不能。super()调用需要知道该方法属于哪个类,以便在基类中搜索重写方法。

如果你通过了self.__class__(或者更好的是,type(self)),那么super()就被错误地指定了搜索方法的起始点,最终会再次调用它自己的方法。

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
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()

演示:

1
2
3
4
5
6
7
8
9
10
11
12
>>> 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而不是DerivedDerived.method()中。

在这个例子中,Subclass的mro是[Subclass, Derived, Base]super()需要知道从哪里开始搜索任何重写的方法。通过使用type(self),你告诉它从Subclass开始,然后它会找到Derived.method(),这就是我们开始的地方。


self.__class__可能不是一个子类,而是一个孙子或更小的类,导致了一个堆栈中断循环。