-2

Let's say we have:

class Parent():
    def __init__(self):
        foo()

    def foo(self):
        //do stuff

class Child(Parent):
    def __init__(self):
        Parent.__init__()

class Grandchild(Child):
    def __init__(self):
        Child.__init__()

    def foo(self):
        //different stuff

There are a lot of classes at the Child level that use the same foo(). Grandchild level has a slightly different version of foo, but when Grandchild is initiated, the foo() call in Parent.__init__() uses the Parent.foo() instead of Grandchild.foo().

Is there a correct practice when in comes to this kind of situation?

martineau
  • 119,623
  • 25
  • 170
  • 301
  • We need to see a [mcve]. Your code has a lot of bugs, and I don't just mean the `//do stuff`. Normally, you *would* end up calling `Grandchild.foo` (which would be its own source of bugs because `Grandchild.foo` probably assumes `self` is initialized). – user2357112 Oct 03 '18 at 20:34
  • read about `super()` when you are at it - see [What does super do in python](https://stackoverflow.com/questions/222877/what-does-super-do-in-python) – Patrick Artner Oct 03 '18 at 20:36
  • Read about [Class Inheritance](https://www.tutorialspoint.com/python/python_classes_objects.htm) – stovfl Oct 03 '18 at 20:39
  • FWIW, in Python comments start with a `#` not `//`. – martineau Oct 04 '18 at 16:13

1 Answers1

1

You're not calling the base classes' __init__() methods properly—you need to pass along the self argument to them:

class Parent:
    def __init__(self):
        self.foo()

    def foo(self):
        print('Parent stuff')

class Child(Parent):
    def __init__(self):
        Parent.__init__(self)

class Grandchild(Child):
    def __init__(self):
        Child.__init__(self)

    def foo(self):
        print('Grandchild stuff')

if __name__ == '__main__':
    gc = Grandchild()  # -> Grandchild stuff

If you use super() instead of explicitly stating the base class, you don't have to do that:

class Parent:
    def __init__(self):
        self.foo()

    def foo(self):
        print('Parent stuff')

class Child(Parent):
    def __init__(self):
#        Parent.__init__(self)
        super().__init__()

class Grandchild(Child):
    def __init__(self):
#        Child.__init__(self)
        super().__init__()

    def foo(self):
        print('Grandchild stuff')

if __name__ == '__main__':
    gc = Grandchild()  # -> Grandchild stuff

Another advantage is that you likely wouldn't have to change the code in a subclass' __init__() method if you changed its base class.

martineau
  • 119,623
  • 25
  • 170
  • 301
  • While this is true, omitting `self` in the superclass constructor calls would lead to a TypeError, not to calling `Parent.foo`. – user2357112 Oct 03 '18 at 20:58
  • @user2357112: Not sure what point you're trying to make. I never said that leaving it out would call `Parent.foo`. THe problem with the OP's code is it doesn't construct the subclasses properly—the `__init__()` method is both of them doesn't call their superclass' `__init__()` because it's coded wrong. The code in the OP's question is somewhat misleading in the sense that it's not run-able (as well as not not properly calling super class `__init__()` methods). – martineau Oct 04 '18 at 02:53
  • The question says "when Grandchild is initiated, the foo() call in Parent.__init__() uses the Parent.foo() instead of Grandchild.foo()", which doesn't really make sense and needs a better code sample. You've addressed the lack of `self` in the constructor calls, but that seems to be an artifact of the questioner making up the code snippet. Your answer doesn't have anything in it related to which version of `foo` gets called, which seems to be the core of the question. – user2357112 Oct 04 '18 at 02:59
  • I think the content of your post is true, but not an answer to the question. The question doesn't seem to be answerable in its current state, and I believe it should be closed. – user2357112 Oct 04 '18 at 03:00
  • @user2357112: In my opinion it answers the question because it shows that the whole problem is with how the code was written—and if the subclass `__init__()` methods are written properly, then instances will start behaving the way the OP desires/expects. – martineau Oct 04 '18 at 06:36