0

I dont understand why the childs method set_state() is called here, when i call it from the __init__() method of the base class:

class base():
    def __init__(self, x):
        self.set_state(x)

    def set_state(self, x):
        self.x = x
        print("base")

class child(base):
    def __init__(self, x, y):
        super().__init__(x)
        self.set_state(y)

    def set_state(self, y):
        self.y = y
        print("child")

test = child(1, 2)

Output is:

child
child
taras
  • 6,566
  • 10
  • 39
  • 50
kakimo
  • 9
  • 1
  • 2
    that's how inheritance works. – Daniel Aug 12 '18 at 10:44
  • 2
    Why _wouldn't_ it be called? The `self` variable is a name for a `child` object, so when you look up the name `set_state` on `self`, you get `child.set_state` (bound to `self`). – abarnert Aug 12 '18 at 10:44
  • 2
    If you're coming from another language: All methods are virtual in python. – Aran-Fey Aug 12 '18 at 10:46
  • That wasn't a facetious question. If you can explain what model you have in your head that would lead you to expect anything else to happen, we can probably explain where you're confused. But without that, I'm kind of baffled. Unless you're coming from, say, C++, and just didn't know that Python doesn't need a `virtual` keyword, because all methods are always virtual, or something like that? – abarnert Aug 12 '18 at 10:47
  • And adding to @Aran-Fey's comment, if you do come from a different language, chances are that you want to be careful with calling virtual methods in constructors there as well (not that `__init__` is really constructor in the Java/C# sense of the word). For instance, you would [see the exact same thing happening in C#](https://stackoverflow.com/q/119506/5085211). – fuglede Aug 12 '18 at 10:49
  • @abarmert It's not about virtual or not. In C++, virtual methods are bound to the most recently constructed entity so when you're calling a virtual method from the base's ctor, _base_ implementation of the method is chosen, if any. If, at this moment, you called child's implementation without child having been properly constructed yet, having a consistent state, well... Here, though, base's `__init__` is called explicitly and the fact that all the methods available by this moment are those of derived class's object, without the latter possibly even being in a valid state... well, conventions. – bipll Aug 12 '18 at 10:52

1 Answers1

2

This is common to all polymorphic languages. The definition of polymorphism is that the actual (most derived) type of the object determines which version of a method is called, even if all you know at the calling point is that it is an instance of some superclass.

If you need to override this and absolutely only ever call the superclass method from the superclass init, name it with two leading underscores as in __set_state. This invokes pythons name mangling rules so that a subclass can't (easily) override the method - however, it also makes it uncallable (or again not easily callable) from outside code. But the polymorphic behaviour is usually what you want, which is why it is the default in Python (as opposed to, say, C++ where methods are not polymorphic unless you expressly declare them as virtual).

lvc
  • 34,233
  • 10
  • 73
  • 98
  • You beat me to it :D – Daniel Aug 12 '18 at 10:49
  • Ok, thank you, that was really helpful. I obviously misunderstood the working of super(), I thought it would force not only the method called to be from the base class but all subsequent calls. – kakimo Aug 12 '18 at 13:43