o7planning

Inheritance and polymorphism in Python

  1. Introduction
  2. Inheritance in Python
  3. Override method
  4. Abstract Method
  5. Multiple inheritance
  6. issubclass and isinstance function
  7. Polymorphism with function

1. Introduction

Inheritance and polymorphism - this is a very important concept in Python. You must understand it better if you want to learn Python.
Before you start learning about "Inheritance in Python", make sure you have the concept of "Class and object", if not, let's learn it:
This document is based on:
  • Python 3.x

2. Inheritance in Python

Python allows you to create an extension class from one or more other classes. This class is called a derived class, or a subclass.

The child class inherits the attributes, methods, and other members from the parent class. It can also override methods from the parent class. If the child class does not define its own constructor, by default, it will inherit the constructor of the parent class.
Unlike Java, CSharp and several other languages, Python allows multiple inheritance. A class can be extended from one or more parent classes.
We need a few classes to participate in examples.
  • Animal: Class simulate an animal.
  • Duck: Subclass of Animal.
  • Cat: Subclass of Animal.
  • Mouse: Subclass of Animal.
In Python, constructor of class used to create an object (instance), and assign the value for the attributes.
Constructor of subclasses always called to a constructor of parent class to initialize value for the attributes in the parent class, then it start assign value for its attributes.
Example:
animal.py
class Animal :  

    # Constructor
    def __init__(self, name):
        
        # Animal class has one attribute: 'name'.
        self.name= name 
    
    # Method    
    def showInfo(self):
        print ("I'm " + self.name)
        
    # Method: 
    def move(self):
        print ("moving ...")
Cat is the class that inherits from the Animal class, it also has its attributes.
cat.py
from animal import Animal       
        
# Cat class extends from Animal.
class Cat (Animal): 
    
    def __init__(self, name, age, height):
        # Call to contructor of parent class (Animal)
        # to assign value to attribute 'name' of parent class.
        super().__init__(name)
        
        self.age = age 
        self.height = height
    
    # Override method.
    def showInfo(self):
        
        print ("I'm " + self.name)
        print (" age " + str(self.age))
        print (" height " + str(self.height))
catTest.py
from cat import Cat


tom = Cat("Tom", 3, 20)

print ("Call move() method")

tom.move()

print ("\n")
print ("Call showInfo() method")

tom.showInfo()
Running catTest module:
Call move() method
moving ...

Call showInfo() method
I'm Tom
 age 3
 height 20
What's happened when you create an object from constructor . How does it call up a constructor of the parent class? Please see the illustration below:
With the above illustration you see that, constructor of parent class is called in constructor of subclass, it will assign values to the attributes of the parent class, then the attributes of the subclass.

3. Override method

By default, child classes inherit methods from the parent class, but parent classes can override the method of the parent class.
mouse.py
from animal import Animal       
        
# Mouse class extends from Animal.
class Mouse (Animal): 
    
    def __init__(self, name, age, height):
        # Call to contructor of parent class (Animal)
        # to assign value to attribute 'name' of parent class.
        super().__init__(name)
        
        self.age = age 
        self.height = height
    
    # Override method.
    def showInfo(self):
        # Call method of parent class.
        super().showInfo()
        print (" age " + str(self.age))
        print (" height " + str(self.height))
    
    # Override method.
    def move(self):
        print ("Mouse moving ...")
Test
mouseTest.py
from mouse import Mouse


jerry = Mouse("Jerry", 3, 5)

print ("Call move() method")

jerry.move()

print ("\n")
print ("Call showInfo() method")

jerry.showInfo()
Output:
Call move() method
Mouse moving ...

Call showInfo() method
I'm Jerry
 age 3
 height 5

4. Abstract Method

The concept of an abstract method or abstract class is defined in languages such as Java, C #. But it is not clearly defined in Python. However, we have a way to define it.
A class called as abstract defines abstract methods and child class must override these methods if you want to use them. The abstract methods always throw the exception NotImplementedError.
abstractExample.py
# An abstract class.
class AbstractDocument :
    
    def __init__(self, name):
        
        self.name = name
        
    # A method can not be used, because it always throws an error.
    def show(self):
        raise NotImplementedError("Subclass must implement abstract method")    
    
    

class PDF(AbstractDocument):
    
    # Override method of parent class
    def show(self):
        print ("Show PDF document:", self.name)
        
        
class Word(AbstractDocument):     
    
    def show(self):
        print ("Show Word document:", self.name)

# ----------------------------------------------------------
documents = [ PDF("Python tutorial"),
              Word("Java IO Tutorial"),
              PDF("Python Date & Time Tutorial") ]     


for doc in documents :
    
    doc.show()
Output:
Show PDF document: Python tutorial
Show Word document: Java IO Tutorial
Show PDF document: Python Date & Time Tutorial
The example above demonstrates Polymorphism in Python. A Document object can be represented in various forms (PDF, Word, Excel, ...).
Another example illustrates polymorphism: When I talk about an Asian people, it's quite abstract, he can be Japanese, Vietnamese, or Indian. However, there are features of Asian people.

5. Multiple inheritance

Python allows multiple inheritance, which means you can create an extension class from two or more other classes. The parent classes can have the same attributes, or the same methods, ....The child class will prioritize to inherit attributes, methods, ... of the first class in a list of inheritance
multipleInheritanceExample.py
class Horse: 
    maxHeight = 200; # centimeter
    
    def __init__(self, name, horsehair):
        self.name = name
        self.horsehair = horsehair 

    def run(self):
        print ("Horse run")   
     
    def showName(self):
        print ("Name: (House's method): ", self.name)   
        
    def showInfo(self):
        print ("Horse Info")   

class Donkey: 
    def __init__(self, name, weight):        
        self.name = name
        self.weight = weight   
        
    def run(self):
        print ("Donkey run")     
        
    def showName(self):        
        print ("Name: (Donkey's method): ", self.name)   

    def showInfo(self):
        print ("Donkey Info")               
  
# Mule class inherits from Horse and Donkey.
class Mule(Horse, Donkey): 
    def __init__(self, name, hair, weight): 
        Horse.__init__(self, name, hair)  
        Donkey.__init__(self, name, weight) 
    
    def run(self):   
        print ("Mule run")   

    def showInfo(self):
        print ("-- Call Mule.showInfo: --")
        Horse.showInfo(self)
        Donkey.showInfo(self) 
# ---- Test ------------------------------------
# 'maxHeight' variable inherited from Horse class. 
print ("Max height ", Mule.maxHeight)

mule = Mule("Mule", 20, 1000) 
mule.run() 
mule.showName()  
mule.showInfo()
Output:
Max height  200
Mule run
Name: (House's method): Mule
-- Call Mule.showInfo: --
Horse Info
Donkey Info
mro() method
The mro () method lets you view the list of parent classes of a certain class. Let's see the example below:
mroExample.py
class X: pass
class Y: pass
class Z: pass

class A(X,Y): pass
class B(Y,Z): pass

class M(B,A,Z): pass

# Output:
# [<class '__main__.M'>, <class '__main__.B'>,
# <class '__main__.A'>, <class '__main__.X'>,
# <class '__main__.Y'>, <class '__main__.Z'>,
# <class 'object'>]
print(M.mro())
Note: In Python, the pass statement is like a null (or empty) command, it does nothing, if the class or method has no content, you still need at least one statement, let's use pass.

6. issubclass and isinstance function

Python has two useful functions:
  • isinstance
  • issubclass
isinstance
The isinstance function helps you to check whether "something" is an object of a certain class or not.
issubclass
The issubclass function checks whether this class is the child of another class or not.
isinstancesubclass.py
class A: pass
class B(A): pass 
# True
print ("isinstance('abc', object): ",isinstance('abc', object))
# True
print ("isinstance(123, object): ",isinstance(123, object))

b = B()
a = A()

# True
print ("isinstance(b, A): ", isinstance(b, A) )
print ("isinstance(b, B): ", isinstance(b, B) )

# False
print ("isinstance(a, B): ", isinstance(a, B) )

# B is subclass of A? ==> True
print ("issubclass(B, A): ", issubclass(B, A) )

# A is subclass of B? ==> False
print ("issubclass(A, B): ", issubclass(A, B) )
Output:
isinstance('abc', object): True
isinstance(123, object): True
b = B()
a = A()
isinstance(b, A): True
isinstance(b, B): True
isinstance(a, B): False
isinstance(B, A): True
isinstance(A, B): False

7. Polymorphism with function

Here I create two classes such as English and French. Both of the classes have the greeting () method. Both create different greetings. Create two corresponding objects from the two classes above and call the actions of these two objects in the same function (intro function).
people.py
class English:
    def greeting(self):      
        print ("Hello")
      
class French:
    def greeting(self):
        print ("Bonjour")

def intro(language):  
    language.greeting()
  
flora  = English()
aalase = French() 
intro(flora)
intro(aalase)
Run the example:
Hello
Bonjour