Programmer's Python - Single Inheritance
Written by Mike James   
Monday, 06 August 2018
Article Index
Programmer's Python - Single Inheritance
Basic Inheritance
Overriding
Super Super and the mro

Overriding

You can of course extend the derived class by adding new attributes.

What about overriding inherited attributes?

This is simple because to override a method all you have to do is define it in the child. As it will be found earlier in the search of the inheritance chain it will be used in preference to any other method of the same name.

For example:

class child(base):
   def myMethodBase(self):
     print("Child method")

Now when you call the method:

childObject=child()
childObject.myMethodBase()

you will see “Child method”.

The inheritance mechanism used by Python is similar to the prototype chain used by JavaScript. All of the classes involved in the inheritance are searched in the order they are inherited, and the first one that has the method supplies it. If this happens to be the first class in the chain then so be it, and it has overridden all of the other definitions of the method or attribute.

Overriding is simple but what if you want to call the base method?

To answer this question we need to look at the Super built-in function.

Simple Super()

If the overriding method wants to call the base method that it has overridden, then all it has to do is use super().method which calls the specified method in a superclass even if it has been defined in the current class.

Super is a very misunderstood function because it seems to do what similar facilities in other languages do – it doesn’t.

Super isn’t just a reference to the class next up in the inheritance chain – it is a reference to any class higher in the inheritance chain than the current class.

That is, super searches all of the inherited classes for the method and returns the first one it finds. It follows the same attribute resolution procedure that is normally used but it leaves out the class it is used in. This means it will call the method in the first class that has it defined, not including the current class. If no class has that method defined then an exception is thrown.

The important point is that super isn’t just a reference to the immediate superclass of the current class.

For example:

class A: pass
class B(A):
   def myMethod(self):
     print("class B")
class C(B): pass
class D(C):
   def myMethod(self):
     print("class D")
     super().myMethod()

This defines four classes A, B, C and D and each inherits from the previous class. This makes the inheritance chain:

A → B → C → D

which is read as A is the base class for B, B is the base class for C and so on.

When you call a method or attribute in class D, first class D is checked for a definition and if found it is used. If not class C is searched, then B then A and the first definition is used.

That is the search order for attribute access is:

D → C → B → A

The call to myMethod within D.myMethod uses super and so the search order for this starts from the first superclass i.e. C. That is, the search order misses out D and it is:

C → B → A

As myMethod is defined in class B it is this method that is used.

So if you try:

d=D()
d.myMethod()

You will see “class D” followed by “class B” indicating the method definitions used.

Notice that you don’t have to be in myMethod to use a call to:

super().myMethod

the super function is completely general.

For example in:

class D(C):
    def myMethod2(self):
        print("class D")
        super().myMethod()

super().myMethod() will call myMethod in the first class in the inheritance chain that defines it – not including class D of course.

That is, super().attribute uses the same resolution method as does attribute but without including the current class in the search.

Also notice that unlike other languages Python’s super() searches for any attribute not just a method.

For example:

super().myAttribute

searches the inheritance chain for myAttribute not including the current class.

Super super() and the mro

The Python super already goes well beyond what you might expect in other languages but there is more. The order that methods or more generally attributes are searched for is stored in the __mro_ magic variable in every class. Although __mro__ stands for method resolution order it specifies the search order for any attribute not just methods.

For example, if you try:

print(D.__mro__)

for the previous inheritance chain i.e.:

A → B → C → D

then what you see is:

(<class '__main__.D'>, <class '__main__.C'>,
<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

where the __mro__ has included object which is the start of all inheritance chains.

Python’s super() uses __mro__ to determine the search order.

The full version of super() is:

super(class, self)

where self is used to retrieve the __mro__ from the class that created it, i.e.

type(self).__mro__

and class is the class to start the search for super from.

<ASIN:1871962587>



Last Updated ( Monday, 06 August 2018 )