I'm wondering how come the self.name is 'abc' when the super().__init__('abc') gets called, but it becomes 'Nicky' when super().override() is called?
Is it because the Derived instance hasn't been created yet during the time super().__init__('abc') is called so the Base class's properties are used instead?
class Base():
def __init__(self, name):
self.name = name
self.base = 'base class'
print('Base', self.name)
def override(self):
print('Base-override', self.name)
class Derived(Base):
def __init__(self, name, age):
super().__init__('abc')
self.name = name
self.age = age
def override(self):
super().override()
d = Derived('Nicky', 20) # Base abc
d.override() # Base-override Nicky
CodePudding user response:
You can understand it better if you add more prints
class Base():
def __init__(self, name):
print('Base1', self.__dict__)
self.name = name
self.base = 'base class'
print('Base2', self.name, self.__dict__)
def override(self):
print('Base-override', self.name)
class Derived(Base):
def __init__(self, name, age):
print('Derived1', self.__dict__)
super().__init__('abc')
self.name = name
self.age = age
print('Derived2', self.name, self.__dict__)
def override(self):
super().override()
d = Derived('Nicky', 20) # Base abc
d.override() # Base-override Nicky
Output
Derived1 {}
Base1 {}
Base2 abc {'name': 'abc', 'base': 'base class'}
Derived2 Nicky {'name': 'Nicky', 'base': 'base class', 'age': 20}
Base-override Nicky
There are no different versions for the attribute name
of your object d
, both refers to the same value, don't confuse yourself that name
is different between the parent and child class, after all, it's just the same object, regardless of the class hierarchies.
It's just a matter of what you set last at a point in time. Here, when you called super().__init__('abc')
, you haven't initialized the name "Nicky" in your Derived.__init__()
, thus you saw the value of "abc" first.
CodePudding user response:
It has to do with execution order and how you use the parameters. A class is a collection of data, and has some functions to work on that data. You can use super()
to call an implementation explicitly from the parent class.
There is nothing special about __init__
as a method or name
as an attribute. Your calling sequence is as follows:
Derived('Nicky', 20)
creates a new empty object usingobject.__new__
, then callsDerived.__init__(obj, 'Nicky', 20)
. Remember that the attribute dictionary is empty at this point.Derived.__init__(obj, 'Nicky', 20)
starts out by callingBase.__init__(obj, 'abc')
viasuper()
.Base.__init__(obj, 'abc')
setsobj.name
to'abc'
andobj.base
to'base class'
. It then returns with those two attributes set in the dictionary. This is where the firstprint
happens.Derived.__init__(obj, 'Nicky', 20)
then runs along and setsobj.name
to'Nicky'
, andobj.age
to20
. It then returns. The key point is thatobj.name
is the same attribute as whatBase.__init__
was working on: different methods, same data.Derived('Nicky', 20)
returns the newly created and initialized object, which you assign to the named
.- When you call
d.override
, or any other method, it has access tod.__dict__
as the previous method left it.
Aside from the lesson on how instance data is stored and passed around, this is a lesson on how to design your initializers. Usually, you call super
exactly to avoid doing unnecessary work in the derived class. In __init__
, that means letting the base class handle name information. It also means that override
as currently implemented shouldn't exist: the base implementation will be called on the derived instance anyway, and if that's all you're doing, you don't actually need to override it:
class Base():
def __init__(self, name):
self.name = name
self.base = 'base class'
print('Base', type(self), self.name)
def override(self):
print('Base-override', type(self), self.name)
class Derived(Base):
def __init__(self, name, age):
super().__init__(name)
self.age = age
I've added type(self)
to your printouts so you can see that it's an instance of Derived
that Base
methods are called on when you instantiate Derived
.
CodePudding user response:
Nothing mysterious here.
You are creating the base class with name = 'abc
' but then overriding sef.name
with 'Nicky'.
It is clear from this code:
super().__init__('abc')
self.name = name
self.age = age
That in order for self.name = name
to be executed, the expression super().__init__('abc')
has to be completed.