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.
Inheritance leads to code reusability since a child class reuses all the code written in parent 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:
- Single level Inheritance: There is only one parent class which may have a single child class or more than one child classes.
- 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.
- 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.
# 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.
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.
pass
after class declaration as shown belowclass 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.