<p>您的问题的答案取决于一个非常重要的方面:<strong>您的基类是为多重继承而设计的吗?</strong></p>
<p>有3种不同的情况:</p>
<ol>
<li><h2>基类是不相关的独立类</h2>
<p>如果您的基类是独立的实体,它们能够独立工作,并且彼此不认识,那么它们是为多重继承而设计的<em>而不是</em>。示例:</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>!这就是你的代码不能正常工作的原因。由于diamond继承在python中的工作方式,基类为<code>object</code>的类不应该调用<code>super().__init__()</code></strong>。正如您所注意到的,这样做会破坏多重继承,因为您最终会调用另一个类的<code>__init__</code>,而不是<code>object.__init__()</code>。<em>(<strong>免责声明:</strong>避免<code>super().__init__()</code>在<code>object</code>-子类中使用<code>super().__init__()</code>是我个人的建议,绝不是python社区达成的共识。有些人更喜欢在每一个类中使用<code>super</code>,他们认为如果类的行为不符合您的预期,您可以始终编写<a href="https://en.wikipedia.org/wiki/Adapter_pattern" rel="noreferrer">adapter</a>)</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 href="https://stackoverflow.com/questions/533631/what-is-a-mixin-and-why-are-they-useful">mixin</a>是一个设计为与多重继承一起使用的类。这意味着我们不必手动调用两个父构造函数,因为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>
<li>子类继承自mixin<em>first</em>:<code>class FooBar(FooMixin, Bar)</code>。如果基类的顺序错误,则永远不会调用mixin的构造函数。</li>
</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>