简体   繁体   中英

Multiple Inheritance and calling super()

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()

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.)

How exactly are you instantiating Top objects?

Given your code above, the following works fine:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM