2
votes

I get the error: TypeError: __init__() takes exactly 2 arguments (3 given)

When trying to instantiate an object from the class Top:

super(Middle1, self).__init__(name, "middle")

class Base(object):
    def __init__(self, name, type):
        pass

class Middle1(Base):
    def __init__(self, name):
        super(Middle1, self).__init__(name, "middle1")

class Middle2(Base):
    def __init__(self, name):
        super(Middle2, self).__init__(name, "middle2")

class Middle3(Base):
    def __init__(self, name):
        super(Middle3, self).__init__(name, "middle3")

class Top(Middle1, Middle2, Middle3):
    def __init__(self):
        super(Top, self).__init__("top")

# Here is where it produces the error
if __name__ == '__main__':
    Top()

What am I not understanding about this multiple inheritance issue?

Note: this is python 2.7

EDIT

Ok so I tried something that I think works for my case. This is the equivelent end result, I think it's basically forcing depth first by not calling super and calling each individual __init__ instead.

class Base(object):
    def __init__(self, name, type):
        pass

class Middle1(Base):
    def __init__(self, name, type = "middle1"):
        super(Middle1, self).__init__(name, type)

class Middle2(Base):
    def __init__(self, name, type = "middle2"):
        super(Middle2, self).__init__(name, type)

class Middle3(Base):
    def __init__(self, name, type = "middle3"):
        super(Middle3, self).__init__(name, type)

class Top(Middle1, Middle2, Middle3):
    def __init__(self):
        Middle1.__init__(self, "top")
        Middle2.__init__(self, "top")
        Middle3.__init__(self, "top")

# No errors anymore
if __name__ == '__main__':
    Top()
2
This isn't technically multiple inheritance. Multiple inheritance is when a class inherits from multiple parent classes directly (and is generally not supported in most programming languages).apokryfos
Have you checked that the code file you are executing is the one you are showing here? Because this code does not produce that error ...dhke
You were right. I've edited the code to show my actual situation, Now it produces that error.Esser420
I would refer you to stackoverflow.com/questions/3277367/… this question as well. (Your question should probably be closed as a duplicate of this one, but I think an answer based on your specific code is useful, and I hesitate to use my dupe hammer to close the question unilaterally when I am providing an answer myself.)chepner
It's slightly different from the proposed problem. Mine would work if parents all received same arguments.Esser420

2 Answers

3
votes

First, you have to look at the method resolution order of Top:

>>> for c in Top.__mro__: print c
...
<class '__main__.Top'>
<class '__main__.Middle1'>
<class '__main__.Middle2'>
<class '__main__.Middle3'>
<class '__main__.Base'>
<type 'object'>

This helps you see which class each call to super represents.

Your mistake is thinking that the call to super(Middle1, self) refers to the (only) base class Base of Middle1. It does not: it refers to the the class following Middle1 in the MRO of self.__class__. Since self.__class__ is Top, the next class in line is Middle2, whose __init__ takes only one argument.

To use super correctly from a method, you need to ensure that the method takes the same arguments in every class, because you cannot predict which class's method will be called by looking at the code itself; it depends entirely on the type of the object that initiates the chain of calls, which might be a class you aren't even aware of yet.

There are two posts I suggest reading:

Together, they give you a good understanding of when super can be used correctly and how to avoid the problem you see here.

(In full disclosure, I haven't read either post recently, so I will refrain from trying to summarize the advice presented in each.)

0
votes

How exactly are you instantiating Top objects?

Given your code above, the following works fine:

   topObj = Top()
   middleObj = Middle("middle")
   baseObj = Base("base", "type")