According to the docs on inheritance:
Derived classes may override methods of their base classes. Because methods have no special privileges when calling
When an attribute look-up is performed on an instance of the class, the class dictionary and the dictionaries of its base classes are searched in a certain order (see: Method Resolution Order) for the appropriate method. What is found first is going to get called.
Using the following Spam
example:
class Spam:
def produce_spam(self):
print("spam")
def get_spam(self):
self.produce_spam()
class SuperSpam(Spam):
def produce_spam(self):
print("super spam")
Spam
defines the functions produce_spam
and get_spam
. These live in its Spam.__dict__
(class namespace). The sub-class SuperSpam
, by means of inheritance, has access to both these methods. SuperSpam.produce_spam
doesn't replace Spam.produce_spam
, it is simply found first when the look-up for the name 'produce_spam'
is made on one of its instances.
Essentially, the result of inheritance is that the dictionaries of any base classes are also going to get searched if, after an attribute look-up on the sub-class is made, the attribute isn't found in the sub-class's dictionary.
When the function get_spam
is first invoked with:
s = SuperSpam()
s.get_spam()
the sequence of events roughly goes like this:
SuperSpam
s __dict__
for get_spam
.SuperSpam
s __dict__
look into the dictionaries of it's base classes (mro
chain). Spam
is next in the mro
chain, so get_spam
is found in Spam
's dictionary.Now, when produce_spam
is looked up in the body of get_spam
with self.produce_spam
, the sequence is much shorter:
SuperSpam
's (self
) __dict__
for produce_spam
.produce_spam
is found in the __dict__
first so that gets fetched.