Inheritance in python / How to create child classes in python

What is inheritance
Inheritance is one of the prominent features of Object Oriented Programming(OOPs). In fact, a language which does not support inheritance should not be called an Object Oriented Programming language.
Inheritance involves more than one class where a class is a Parent and other classes are its children. This parent-child relationship can be at a single level where there is only one parent class and single or multiple child classes at the same level or at multiple levels where a parent class has child classes which also have their own children, these grand children may have their children and so on or a child class can have more than one parent classes.

A child class is said to inherit(or extend) a parent class and it has all the attributes of its parent class(or classes). That is, a child class contains all the attributes(instance variables and methods) of its parent class.
Inheritance leads to code reusability since a child class reuses all the code written in parent class.

Parent class is also called Base class and child class is also called Derived class.

Types of inheritance
As discussed above, inheritance is related to parent and child classes. This relationship may be of more than one type and based on the type of relationship, inheritance can be of following types:

  1. Single level Inheritance: There is only one parent class which may have a single child class or more than one child classes.
  2. Multi level Inheritance: A class has one or more child which further has children and so on. All the classes above a class at any level are its parents. That is, if B is the child of A and C is the child of B, then A and B are parents of C and A is the parent of B and so on.
  3. Multiple Inheritance: A child class has more than one parent. This type of inheritance is not supported in all Object Oriented Programming languages such as Java. For detailed insight on multiple inheritance in python, refer this post.

Syntax
In python, a class can extend another class using the following syntax.

class ParentClass:
# parent class methods

class ChidClass(ParentClass):
# child class methods

If a class wants to extend a class, enclose the name of extended(or parent) class within parenthesis after the name of child class.

Example,

# Parent class
class Fruit:
    # parent class constructor
    def __init__(self, name, color):
        self.color = color
        self.name = name

    # parent class method
    def printDetails(self):
        print("Name = "+self.name+", Color = "+self.color)


# Child class
class Apple(Fruit):
    # child class constructor
    def __init__(self, name, color, price):
        # call parent class constructor
        Fruit.__init__(self, name, color)
        # initialize child class variable
        self.price = price

    # child class method
    def getPrice(self):
        print("Price = "+str(100)+" bucks per kg")


# create child class object
childObject = Apple("Apple", "red", 100)
# call method from parent class
childObject.printDetails()
# call method from child class
childObject.getPrice()

Above code has a parent class named Fruit whose constructor takes two arguments which are used to initialize its instance variables. It also has a method which accesses both its instance variables and prints their values.
A new class named Apple is created which is the child class of Fruit. Its constructor calls its parent class constructor and takes 3 arguments. Two out of these 3 arguments are supplied to parent class constructor and third one is used to initialize its own instance variable. It also has a method getPrice which accesses the instance variable created in the class itself.

Thus, the child class has 3 instance variables(two defined in the parent class and one inside the class) and two methods(one defined in the parent class and one inside the class). This is what inheritance means.

Variables defined inside the constructor of a class using self become instance variables of the class.

Notice how parent class constructor is invoked from child class constructor using the name of parent class and supplying it the required values. It is also possible to call parent class constructor using super() method as super().__init__(name,color). In this case, there is no need to pass self as it is implicitly supplied.
Now an object of child class is created by providing the required values in its constructor. First the parent class method printDetails is called and then child class method getPrice is called. Following output is generated.

Name = Apple, Color = red
Price = 100 bucks per kg

Remember that child class object has access to its own methods and variables as well as to parent class methods and variables as shown above while parent class object has access to only its own methods and variables. It cannot access its child class methods and variables. Refer example below.

# Parent class
class Fruit:
    # parent class constructor
    def __init__(self, name, color):
        self.color = color
        self.name = name

    # parent class method
    def printDetails(self):
        print("Name = "+self.name+", Color = "+self.color)


# Child class
class Apple(Fruit):
    # child class constructor
    def __init__(self, name, color, price):
        # call parent class constructor
        Fruit.__init__(self, name, color)
        # initialize child class variable
        self.price = price

    # child class method
    def getPrice(self):
        print("Price = "+str(100)+" bucks per kg")


# create parent class object
parentObject = Fruit("Apple","red")
# call parent clas method
parentObject.printDetails()
# call child class method
parentObject.getPrice() # will be an error

Method printDetails is invoked successfully but when getPrice method is invoked, following error is raised.

parentObject.getPrice()
AttributeError: ‘Fruit’ object has no attribute ‘getPrice’

This is because getPrice method does not belong to Parent class.

If you do not want to add a body to a class, that is, you want to make a class empty, then it can be done by writing pass after class declaration as shown below
class Child(Parent): pass

Using super
In terms of class inheritance, super is always used inside a child class to refer to parent class. It is used to invoke parent class constructor and methods from child class. In the above example, suppose you want to invoke parent class constructor from child class constructor and call parent class printDetails from child class method getPrice, then super can be used for this as shown below.

# Parent class
class Fruit:
    # parent class constructor
    def __init__(self, name, color):
        self.color = color
        self.name = name

    # parent class method
    def printDetails(self):
        print("Name = "+self.name+", Color = "+self.color)


# Child class
class Apple(Fruit):
    # child class constructor
    def __init__(self, name, color, price):
        # call parent class constructor
        super().__init__(name,color)
        # initialize child class variable
        self.price = price

    # child class method
    def getPrice(self):
        # call parent class method
        super().printDetails()
        print("Price = "+str(100)+" bucks per kg")


# create child class object
childObject = Apple("Apple", "red", 100)
# call child class method
childObject.getPrice()

Above syntax for super is valid for Python v3 and above. For python v2.x, you need to call parent class constructor as

super(Fruit, self).__init(name, color)

Hiding Parent class members
Sometimes it is required to restrict the visibility of some members of a class to itself only not making them accessible to its child classes as well. In python, it is possible that an instance variable or a method is hidden from its child classes. This is done by prefixing their name with double underscore(__). Such members of a class are also called private members. Trying to access them will raise an error as shown below.

class Parent:
    def __init__(self):
        # hidden instance variable
        self.__hidethis = 10
        self.showthis = 20

    # hidden method
    def __cannotaccess(self):
         print("Accessible only to parent")

class Child(Parent):pass

c = Child()
# no problem
print(c.showthis)
# will be an error
c._cannotaccess()
# will be an error
print(c.hidethis)

Child class tries to access the restricted members and gets the following error

c._cannotaccess()
AttributeError: ‘Child’ object has no attribute ‘_cannotaccess’

This post focuses on the concept of inheritance and its syntax in python. Hope it clarified the concept.
Another important concept is multiple inheritance. Including it here will make this post lengthy and confusing for those who have not known this concept earlier, thus it has been covered in a separate post here.

Leave a Reply