Multi-inheritance problem

coincheung: <p>Hi,</p>
<p>I need to implement a class A, and two children class B and C, and a grand-child D, The code is like this:</p>
<pre><code class="lang-auto">import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.utils.model_zoo as modelzoo
import torch.distributed as dist



class A(nn.Module):

    def __init__(self, ratio=4, *args, **kwargs):
        super().__init__()

        self.conv_base = nn.Conv2d(3, 3 * ratio, 3, 1, 1)


class B(A):

    def __init__(self, b_args, **kwargs):
        super().__init__(ratio=4)

        self.conv1 = nn.Conv2d(4, 3, 1, 1, 0)


class C(A):

    def __init__(self, c_args, **kwargs):
        super().__init__(ratio=4)

        self.conv2 = nn.Conv2d(4, 3, 1, 1, 0)


class D(B, C):

    def __init__(self, b_args, c_args):
        super().__init__(b_args=b_args, c_args=c_args)

        self.conv3 = nn.Conv2d(4, 3, 1, 1, 0)


b_args = dict(a=1)
c_args = dict(b=2)
model = D(b_args, c_args)
</code></pre>
<p>And I observed this error message:</p>
<pre><code class="lang-auto">    super().__init__(ratio=4)
TypeError: C.__init__() missing 1 required positional argument: 'c_args'
</code></pre>
<p>Would you tell me how could I make this work?</p>

FarshaWarsha: <p>The issue arises because <code>D</code> inherits from both <code>B</code> and <code>C</code>, and when <code>super()</code> is used in <code>D.__init__</code>, Python’s method resolution order (MRO) calls <code>B.__init__</code>, which subsequently calls <code>A.__init__</code>. However, <code>C.__init__</code> is not automatically called, so its required <code>c_args</code> is missing.</p>
<p>To fix this, explicitly call the <code>__init__</code> methods of both parent classes (<code>B</code> and <code>C</code>) within <code>D.__init__</code>.<br>
import torch<br>
import torch.nn as nn</p>
<p>class A(nn.Module):<br>
def <strong>init</strong>(self, ratio=4, *args, **kwargs):<br>
super().<strong>init</strong>()<br>
self.conv_base = nn.Conv2d(3, 3 * ratio, 3, 1, 1)</p>
<p>class B(A):<br>
def <strong>init</strong>(self, b_args, **kwargs):<br>
super().<strong>init</strong>(ratio=4, **kwargs)<br>
self.conv1 = nn.Conv2d(4, 3, 1, 1, 0)</p>
<p>class C(A):<br>
def <strong>init</strong>(self, c_args, **kwargs):<br>
super().<strong>init</strong>(ratio=4, **kwargs)<br>
self.conv2 = nn.Conv2d(4, 3, 1, 1, 0)</p>
<p>class D(B, C):<br>
def <strong>init</strong>(self, b_args, c_args):<br>
B.<strong>init</strong>(self, b_args=b_args)<br>
C.<strong>init</strong>(self, c_args=c_args)<br>
self.conv3 = nn.Conv2d(4, 3, 1, 1, 0)</p>
<h1><a name="p-460801-example-usage-1" class="anchor" href="#p-460801-example-usage-1"></a>Example usage</h1>
<p>b_args = dict(a=1)<br>
c_args = dict(b=2)<br>
model = D(b_args, c_args)<br>
Explicit Parent Initialization: In <code>D.__init__</code>, explicitly call <code>B.__init__</code> and <code>C.__init__</code> with their respective arguments.<br>
Avoid Super with Multiple Inheritance: Using <code>super()</code> in complex multiple inheritance setups can lead to skipped initializations due to MRO. Explicit calls ensure all parent classes are initialized properly.</p>
<p>This structure ensures all required arguments (<code>b_args</code> and <code>c_args</code>) are passed and handled correctly.</p>

coincheung: <p>I still have error message:</p>
<pre><code class="lang-auto">Traceback (most recent call last):
  File "tmp.py", line 101, in &lt;module&gt;
    model = D(b_args, c_args)
  File "tmp.py", line 93, in __init__
    B.__init__(self, b_args=b_args)
  File "
TypeError: C.__init__() missing 1 required positional argument: 'c_args'
</code></pre>
<p>Though I have changed my code like this:</p>
<pre><code class="lang-auto">class A(nn.Module):

    def __init__(self, ratio=4, *args, **kwargs):
        super().__init__()

        self.conv_base = nn.Conv2d(3, 3 * ratio, 3, 1, 1)


class B(A):

    def __init__(self, b_args, **kwargs):
        super().__init__(ratio=4)

        self.conv1 = nn.Conv2d(4, 3, 1, 1, 0)


class C(A):

    def __init__(self, c_args, **kwargs):
        super().__init__(ratio=4)

        self.conv2 = nn.Conv2d(4, 3, 1, 1, 0)


class D(B, C):

    def __init__(self, b_args, c_args):
        #  super().__init__(b_args=b_args, c_args=c_args)
        B.__init__(self, b_args=b_args)
        C.__init__(self, c_args=c_args)

        self.conv3 = nn.Conv2d(4, 3, 1, 1, 0)


b_args = dict(a=1)
c_args = dict(b=2)
model = D(b_args, c_args)
</code></pre>