3.7 Inheritance: Tracing Initialization#
Let’s trace what happens when we initialize an object in the context of inheritance. We’ll use a fresh example about monsters:
from typing import Any
class Monster:
def __init__(self, name: str) -> None:
self.name = name
self.hunger = 100
self.energy = 0
def eat(self, item: Any) -> None:
raise NotImplementedError
def sleep(self, minutes: int) -> None:
self.energy += minutes
def __str__(self) -> str:
return self.name + 'Boo!'
class Gremlin(Monster):
def __init__(self, name: str) -> None:
Monster.__init__(self, name)
self.stuffy = 'Bunny'
def eat(self, item: Any) -> None:
# Eating makes Gremlins more hungry!
self.hunger = self.hunger + 10
def __str__(self) -> str:
return self.name + 'Mwahaha!'
if __name__ == '__main__':
m = Gremlin('Julius')
In the main block, when we call Gremlin('Julius') we invoke the three-step
process for creating an instance of a class:
Create a new
Gremlinobject behind the scenes.Call
__init__with the new object passed to the parameterself, along with the other argument,'Julius'.Return the new object (which we then assign to variable `m``, which must first be created).
Let’s go through these steps.
In step 1, a new Gremlin object is created for us, and is currently empty.
This is the state of memory afterwards:
In step 2, the __init__ method for Gremlin is called,
with the new object passed as the parameter self,
and the other argument, 'Julius', passed as name.
The Gremlin object is still empty.
At the moment after the Gremlin initializer has been called, this is the
state of memory:
If we look at the code for the Gremlin initializer, we see that
the first thing this method does is call the initializer for Monster,
passing the values of self and name.
The Gremlin object is still empty.
The Monster initializer has three lines of code.
It use self to access the new Gremlin object
and defines three new attributes within it, giving each a value:
When the Monster initializer returns, we resume the Gremlin initializer
where we left off.
It has one line of code left, which uses self to access the Gremlin object
and put a new attribute called stuffy inside it:
Finally, step 2 is done and we pop the Gremlin initializer call from the stack.
We are back in the __main__ block where we were in the middle of completing
an assignment statement: m = Gremlin('Julius').
We have evaluated the right-hand side, yielding the id of a Gremlin object, id106.
We will assign it to m, but since there is no m in the frame where we are
working, we make one first:
A lot had to happen to execute that one-line main block!