<p>您的问题的答案取决于一个非常重要的方面:<strong>您的基类是为多重继承设计的吗?</strong></p>
<p>有3种不同的场景:</p>
<ol>
<li><h2>基类是不相关的独立类</h2>
<p>如果您的基类是能够独立运行的独立实体,并且它们彼此不认识,那么它们不是为多重继承而设计的。例如:</p>
<pre><code>class Foo:
def __init__(self):
self.foo = 'foo'
class Bar:
def __init__(self, bar):
self.bar = bar
</code></pre>
<p><strong>重要提示:</strong>请注意<code>Foo</code>和<code>Bar</code>都不调用<code>super().__init__()</code>!这就是你的代码不能正常工作的原因。由于菱形继承在python中的工作方式,<strong>基类为<code>object</code>的类不应调用<code>super().__init__()</code></strong>。正如您所注意到的,这样做会破坏多重继承,因为您最终会调用另一个类的<code>__init__</code>,而不是<code>object.__init__()</code><em>(<strong>免责声明:</strong>避免<code>object</code>中的<code>super().__init__()</code>-子类是我个人的建议,绝不是python社区的共识。有些人更喜欢在每个类中使用<code>super</code>,他们认为如果类的行为不符合您的预期,您总是可以编写<a href="https://en.wikipedia.org/wiki/Adapter_pattern" rel="noreferrer">adapter</a>。)</em></p>
<p>这也意味着您不应该编写从<code>object</code>继承而没有<code>__init__</code>方法的类。根本不定义<code>__init__</code>方法与调用<code>super().__init__()</code>具有相同的效果。如果类直接从<code>object</code>继承,请确保添加空构造函数,如下所示:</p>
<pre><code>class Base(object):
def __init__(self):
pass
</code></pre>
<p>无论如何,在这种情况下,您必须手动调用每个父构造函数。有两种方法可以做到这一点:</p>
<ul>
<li><p><strong>没有<code>super</code></strong></p>
<pre><code>class FooBar(Foo, Bar):
def __init__(self, bar='bar'):
Foo.__init__(self) # explicit calls without super
Bar.__init__(self, bar)
</code></pre></li>
<li><p><strong>与<code>super</code></strong></p>
<pre><code>class FooBar(Foo, Bar):
def __init__(self, bar='bar'):
super().__init__() # this calls all constructors up to Foo
super(Foo, self).__init__(bar) # this calls all constructors after Foo up
# to Bar
</code></pre></li>
</ul>
<p>这两种方法各有优缺点。如果您使用<code>super</code>,您的类将支持<a href="https://stackoverflow.com/a/33469090/1222951">dependency injection</a>。另一方面,更容易犯错误。例如,如果更改<code>Foo</code>和<code>Bar</code>的顺序(如<code>class FooBar(Bar, Foo)</code>),则必须更新<code>super</code>调用以匹配。如果没有<code>super</code>,您就不必担心这一点,代码的可读性也会更好</p></li>
<li><h2>其中一个类是mixin</h2>
<p>A<a href="https://stackoverflow.com/questions/533631/what-is-a-mixin-and-why-are-they-useful">mixin</a>是一个<em>设计用于多重继承的类。这意味着我们不必手动调用两个父构造函数,因为mixin将自动为我们调用第二个构造函数。因为这次我们只需要调用一个构造函数,所以我们可以使用<code>super</code>来避免硬编码父类的名称</p>
<p>例如:</p>
<pre><code>class FooMixin:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # forwards all unused arguments
self.foo = 'foo'
class Bar:
def __init__(self, bar):
self.bar = bar
class FooBar(FooMixin, Bar):
def __init__(self, bar='bar'):
super().__init__(bar) # a single call is enough to invoke
# all parent constructors
# NOTE: `FooMixin.__init__(self, bar)` would also work, but isn't
# recommended because we don't want to hard-code the parent class.
</code></pre>
<p>这里的重要细节是:</p>
<ul>
<li>mixin调用<code>super().__init__()</code>并传递它接收到的任何参数</李>
<li>子类继承自mixin<em>first</em>:<code>class FooBar(FooMixin, Bar)</code>。如果基类的顺序错误,则永远不会调用mixin的构造函数</李>
</ul></li>
<li><h2>所有基类都是为协作继承而设计的</h2>
<p>为协作继承设计的类非常类似于mixin:它们将所有未使用的参数传递给下一个类。像前面一样,我们只需调用<code>super().__init__()</code>,所有父构造函数都将被链调用</p>
<p>例如:</p>
<pre><code>class CoopFoo:
def __init__(self, **kwargs):
super().__init__(**kwargs) # forwards all unused arguments
self.foo = 'foo'
class CoopBar:
def __init__(self, bar, **kwargs):
super().__init__(**kwargs) # forwards all unused arguments
self.bar = bar
class CoopFooBar(CoopFoo, CoopBar):
def __init__(self, bar='bar'):
super().__init__(bar=bar) # pass all arguments on as keyword
# arguments to avoid problems with
# positional arguments and the order
# of the parent classes
</code></pre>
<p>在这种情况下,父类的顺序并不重要。我们不妨先从<code>CoopBar</code>继承,代码仍然可以工作。但这是唯一正确的,因为所有参数都作为关键字参数传递。使用位置参数会使参数的顺序很容易出错,因此协作类通常只接受关键字参数</p>
<p>这也是我前面提到的规则的一个例外:<code>CoopFoo</code>和<code>CoopBar</code>都继承自<code>object</code>,但它们仍然调用<code>super().__init__()</code>。如果他们不这样做,就不会有合作继承</p></li>
</ol>
<p>一句话:正确的实现取决于您从中继承的类</p>
<P>构造函数为Par类的公共接口的t。如果类被设计为mixin或用于协作继承,则必须对此进行记录。如果文档没有提到这类内容,那么可以安全地假设类<em>不是为协作多重继承而设计的</p>