Home Python Inheritance
Post
Cancel

Python Inheritance

By using inheritance, we may create classes that inherit all the features of their parent classes and allow us to add new ones.

Inheritance in Python

Inheritance in python refers to defining a new class with little or no modification to an existing class. The new class is called derived (or child) class and the one from which it inherits is called the base(or parent) class.

Syntax: ```python class BaseClass: Body of base class

1
2
class DerivedClass(BaseClass):
    Body of derived class ``` The derived class inherits the attributes and methods from the base class where new features can be added to it. This results in re-usability of code. 

Example of Inheritance in Python

Let us define a polygon, a closed figure with 3 or more sides.

1
2
3
4
5
6
7
8
9
10
11
    class Polygon:
        def __init__(self, no_of_sides):
            self.n = no_of_sides
            self.sides = [0 for i in range(no_of_sides)]

        def inputSides(self):
            self.sides = [float(input(f'Enter side {i+1}: ')) for i in range(self.n)]

        def dispSides(self):
            for i in range(self.n):
                print(f'Side {i+1} is {self.sides[i]}')

This class provides data attributes for storing sides, a list of the n sides and the magnitude of each side. The inputSides() method takes in the magnitude of each side and dispSides() displays these side lengths.

A triangle is a 3-sided polygon. Consequently, we can develop a class called Triangle that descended from Polygon. The Triangle class now has access to all of the Polygon class’s characteristics.

We don’t have to define them once more (code reusability). Following is a definition of a triangle.

1
2
3
4
5
6
7
8
9
10
11
    class Triangle(Polygon):
        def __init__(self):
            super().__init__(self,3)

        
        def findArea(self):
            a,b,c = self.sides
            #calculate the semi-perimiter
            s = (a+b+c)/2
            area = (s*(s-a)*(s-b)*(s-c))**0.5
            print(f'Area of the triangle: {area}')

However, class Triangle has a new method findArea() to find and print the area of the triangle. Here is a sample run.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    t = Triangle()

    t.inputSides()
    Enter side 1: 3
    Enter side 2: 5
    Enter side 3: 4

    t.dispSides()
    Side 1 is 3.0
    Side 2 is 5.0
    Side 3 is 4.0

    t.findArea()
    The area of the triangle is 6.0

As we can see, despite without explicitly defining methods like inputSides() and dispSides() for class Triangle, we were still able to use them.

If an attribute is not found in the class itself, the search continues to the base class. This repeats recursively, if the base class is itself derived from other classes.

Method Overriding In Python

In the above example, observe how the __init__() function was defined in the Triangle and Polygon classes. When this occurs, the derived class’s method supersedes the base class’s. This means that the Triangle’s __init__() method is given preference over the Polygon’s init method.

Generally when overriding a base method, we tend to extend the definition rather than simply replace it. The same is being done by calling the method in base class from the one in derived class (calling Polygon.init() from init() in Triangle). Utilizing the integrated feature super would be a better choice (). so, super(). Polygon is similar to __init (3). It is advised to use __init__(self,3).

Two built-in functinos isinstance() and issubclass() are used to check inheritances. The function isinstance() retursnn True if the object is an instance of the class or other classes derived from it. Each and every class in Python inherits from the base class object.

1
2
3
4
5
6
7
8
9
10
11
    isinstance(t, Triangle)
    Output: True

    isinstance(t, Polygon)
    Output: True

    isinstance(t, int)
    Output: False

    isinstance(t, object)
    Output: True

Similarly, issubclass() is used to check for class inheritance.

1
2
3
4
5
6
7
8
    issubclass(Polygon, Triangle)
    Output: False

    issubclass(Triangle, Polygon)
    Output: True

    issubclass(bool, int)
    Output: True

Python Multiple Inheritance

In Python, a class can be derived from more than one base class. This is caleed Multiple Inheritance. In Multiple Inheritance, the features of all the base classes are inherited into the derived class. The syntax for multiple inheritance is similar to single inheritance.

1
2
3
4
5
6
7
8
    class Base1:
        pass

    class Base2:
        pass

    class MultiDerived(Base1, Base2):
        pass

Here, the MultiDerived class is derived from Base1 and Base2 classes which means it inherits attributes and featuers from both of the base classes.

Python Multilevel Inheritance

In Python, we can also inherit from a derived class, it is called Multilevel Inheritance. In such type of inheritance, featuers of the base class as well as the dervied classes are inherited into the new derived class. Example:

1
2
3
4
5
6
7
8
    class Base:
        pass

    class Derived1(Base):
        pass

    class Derived2(Derived1):
        pass

Here, the Derived1 class is derived from the Base class, and the Derived2 class is derived from the Derived1 class.

Method Resolution Order In Python

Every class in Python is derived from the object class. It is Python’s most fundamental type. Since all objects are instances of the object class, all other classes built-in or user-defined—are technically derived classes.

1
2
3
4
5
6
7
8
    print(issubclass(list, object))
    Output: True

    print(isinstance(5.5, object))
    Output: True

    print(isinstance('Hello', object))
    Output: True

In the case of multiple inheritance, the current class is first checked for any specified attribute. If not found, the search continues into parent classes in depth-first,left-right fashion without searching the same class twice.

Therefore, the search order in the MultiDerived class example above is [MultiDerived, Base1, Base2, object]. The criteria used to determine this order are known as Method Resolution Order, and this order is also referred to as linearization of MultiDerived class (MRO).

Both local precedence ordering and monotonicity must be prevented by MRO. It guarantees that a class will always appear before of its parents. The order is the same for tuples of base classes when there are many parents.

MRO of a class can be viewed as the __mro__ attribute or the mro() method. The former returns a tuple while the latter returns a list.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    MultiDerived.__mro__
    (
        <class '__main__.MultiDerived'>,
        <class '__main__.Base1'>,
        <class '__main__.Base2'>,
        <class 'object'>
    )

    MultiDerived.mro()
    [
        <class '__main__.MultiDerived'>,
        <class '__main__.Base1'>,
        <class '__main__.Base2'>,
        <class 'object'>
    ]

Here is a little more complex multiple inheritance example and its visualization along with the MRO.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    # Demonstration of MRO
    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'>,
    # ]

    print(M.mro())


    Output: 
    [
        <class '__main__.M'>, 
        <class '__main__.B'>, 
        <class '__main__.A'>, 
        <class '__main__.X'>, 
        <class '__main__.Y'>, 
        <class '__main__.Z'>, 
        <class 'object'>
    ]
This post is licensed under CC BY 4.0 by the author.