2

Hello i was searching about class inheritance in python and i saw that it supports Multiple Inheritance as well but somehow seems problematic :o I ve found an example:

class ParentOne:
    def __init__(self):
        print "Parent One says: Hello my child!"
        self.i = 1

    def methodOne(self):
        print self.i

class ParentTwo:
    def __init__(self):
        print "Parent Two says: Hello my child"

class Child(ParentOne, ParentTwo):
    def __init__(self):
        print "Child Says: hello"
A=Child()

Output

Child Says: hello

So when child inherits ParentOne and ParentTwo why arent those classes initialised? Should we manually initialize them within the inherit class Child? Whats the correct example so we can see all messages printed using only inheritage?

In fact, it is slightly more complex than that; the method resolution order changes dynamically to support cooperative calls to super(). This approach is known in some other multiple-inheritance languages as call-next-method and is more powerful than the super call found in single-inheritance languages.

How can it be more powerful when it need to be initialized manually? Sorry for all these questions. Thanks in advance.

marr75
  • 5,666
  • 1
  • 27
  • 41
BugShotGG
  • 5,008
  • 8
  • 47
  • 63

5 Answers5

7

This is what super is for:

class ParentOne():
    def __init__(self):
        super().__init__()        
        print("Parent One says: Hello my child!")
        self.i = 1

    def methodOne(self):
        print(self.i)

class ParentTwo():
    def __init__(self):
        super().__init__() 
        print("Parent Two says: Hello my child")

class Child(ParentOne, ParentTwo):
    def __init__(self):
        super().__init__()
        print("Child Says: hello")

A=Child()

prints

Parent Two says: Hello my child
Parent One says: Hello my child!
Child Says: hello
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • Not quite: this is tagged python-3, so super has a different format - just `super().__init__`. – Daniel Roseman Oct 05 '12 at 20:07
  • @DanielRoseman It works this way too. But yeah, the short form is better if you know you're on 3.x (unfortunately, not all of us are). –  Oct 05 '12 at 20:07
  • @unutbu Nice answer. If you please, could you somehow explain what `method resolution order changes dynamically to support cooperative calls to super()` means? Thanks :) – BugShotGG Oct 05 '12 at 20:11
  • I think the word `dynamic` here is referring to the fact that you do not know what method `super().__init__()` is going to run until run-time because it depends on `self`'s MRO. `super().__init__` looks in `self.__class__.mro()` for the *next class* after the current class and calls that class's `__init__`. – unutbu Oct 05 '12 at 20:23
  • In the above example, ParentOne's `__init__` calls ParentTwo's `__init__` even though both classes could have been written by two different developers who did not plan for their `__init__` to call the other's `__init__` at all. For a longer, perhaps clearer, explanation, maybe [this answer](http://stackoverflow.com/a/5034440/190597) will help. – unutbu Oct 05 '12 at 20:25
  • 1
    Mnyaaaahhhhh.... super() is really mostly for when you don't know what your parent classes are, like when you are using mixins. In this case you can just call the classes directly. But you need to know which case you have and when to use which, as you can't mix them. :-) But sure, in this case, super() works, as the whole hierarchy has the same parameters (only self) to `__init__()`. – Lennart Regebro Oct 05 '12 at 20:58
4

The base class methods are not called because you are not calling them. You always have to do this explicitly, no matter if there is a single base or multiple bases. In this simple case, add super().__init__() to all three classes. For more general advice, read Python’s super() considered super! .

2

In your example, you are specifically overriding the inherited init method with the child classes init method. If you want all of them to be run, you can explicitly invoke the parents' init methods with super().

If you had not overridden the init method, then the one from ParentOne would be used in this example.

TimothyAWiseman
  • 14,385
  • 12
  • 40
  • 47
2

It's very simple:

class ParentOne:
    def __init__(self):
        print "Parent One says: Hello my child!"
        self.i = 1

    def methodOne(self):
        print self.i

class ParentTwo:
    def __init__(self):
        print "Parent Two says: Hello my child"

class Child(ParentOne, ParentTwo):
    def __init__(self):
        ParentOne.__init__(self)
        ParentTwo.__init__(self)
        print "Child Says: hello"

A=Child()

Problem solved. You can also use super() but in this case you do not need to. Note that you can't mix the two methods, you either need to call super() in all the classes in the hierarchy, or none of them.

Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251
0

The correct example is som,ething along (Python3):

class BaseClass:
    def __init__(self):
        print("Initializing base")

class ParentOne(BaseClass):
    def __init__(self):
        super().__init__()
        print("Initializing parent 1")

class ParentTwo(BaseClass):
    def __init__(self):
        super().__init__()
        print("Initializing parent 1")

class Child(ParentOne, ParentTwo):
    def __init__(self):
        super().__init__()
        print("Initializing child")

c = Child()

Python defines the "super" built-in that correctly resolves the next-to-be-called method, using a well described method resolution order - so, it is not "prtoblematic" at all, - to the contrary, it works quite well on corner cases other languages do have problem - it is described here: http://www.python.org/download/releases/2.3/mro/

jsbueno
  • 99,910
  • 10
  • 151
  • 209
  • 1
    Note that in this specific case, `BaseClass` is not needed, as `object` also accepts `.__init__()` and it's implicitly the base class of the `Parent*` classes. It becomes necessary (and recommended) once the method does not exist "further up" or has a incompatible signature. –  Oct 05 '12 at 20:16