Newby Coder header banner

Python Inheritance

Python Inheritance

Inheritance refers to defining a new class with little or no modification to an existing class

Inheritance allows to define a class that takes all the methods and properties from parent class and allows to add more functions

Parent class is the class being inherited from, also called base class

Child class is the class that inherits from another class, also called derived class

Python Inheritance Syntax

class BaseClass:
  Body of base class

class DerivedClass(BaseClass):
  Body of derived class 

Derived class is declared with the BaseClass inside parentheses

Example of Inheritance in Python

Consider a class called File defined as follows

import os

class File:
    def  __init__(self,  file_type, file_name):
        self.file_type = file_type
        self.file_name = file_name

    def fileSize(self):
        return os.path.getsize(self.file_name)

This class has data attributes to store the name of a file as file_name and its type file_type and method fileSize() returns the size of the file

A class called Image can be created which inherits fromFile

This makes all the attributes of class File to be available in Image, and need not be defined again (code re-usability)

from PIL import Image as PilImage

class Image(File):

    def __init__(self, file_name):
        img = PilImage.open(file_name)
        File.__init__(self, img.format, file_name)

    def getHeight(self):
        im = PilImage.open(self.file_name)
        return im.size[1]

    def getWidth(self):
        im = PilImage.open(self.file_name)
        return im.size[0]
         

Class Image has new methods getHeight() and getWidth() to find the height and width of an Image

Here is a sample run, assuming a file test.jpg exists in the same directory where it is run :

>>> t = Image("test.jpg")
>>> t.fileSize()
13123
>>> t.getHeight()
500
>>> t.getWidth()
800

It shows that class Image could use method fileSize() of class File

If an attribute is not found in a class, search continues to its base class

This repeats further, if the base class is itself derived from other classes

Method Overriding in Python

A subclass can override methods of its parent class

This is done in case the subclass requires a different or additional functionality for the same method than its Parent

In the above example, __init__() method was defined in both classes, File and Image

This denotes that __init__() in Image gets preference over the same in File, when called by an object of Image

Here, the __init__() method of File is also called from __init__() in Image (denoted by the line File.__init__(self, img.format, file_name))

The same can be done by using built-in function super(), which refers to the parent of a derived class

So, File.__init__(self, img.format, file_name) can be replaced with super().__init__(self, img.format, file_name)

Example

#!/usr/bin/python
# define parent class
class Parent:
    def myMethod(self):
        print'Calling parent method'

# define child class
class Child(Parent):
    def myMethod(self):
        print'Calling child method'

# instance of child
c =Child()
c.myMethod() #child calls overridden method 

When the above code is executed, it produces the following output :

Calling child method

isinstance() and issubclass() methods

Two built-in functions isinstance() and issubclass() can be used to check inheritance

The isinstance(obj, Class) boolean function returns true if obj is an instance of class Class or is an instance of a subclass of Class

Every class in Python inherits from the base class object

>>> isinstance(t, Image)
True
>>> isinstance(t, File)
True
>>> isinstance(t,int)
False
>>> isinstance(t,object)
True 

The issubclass(sub, sup) boolean function returns true if the given class sub is a subclass of the class sup

>>> issubclass(File, Image)
False
>>> issubclass(Image, File)
True
>>> issubclass(bool, int)
True 

Multiple Inheritance

A class can be inherited from multiple parent classes as follows :

# define your class A
class A:
.....

# define your class B
class B:
.....

# subclass of A and B
class C(A, B):
.... 

For example, consider a class Shared as

class Shared:
    def __init__(self, userList):
        self.users = userList

    def canOpen(self, username):
        if username in self.users:
            return True
        else:
            return False

Then a class SharedImage can be defined as

class SharedImage(Image, Shared):
    def __init__(self, file_name, userList):
        Image.__init__(self, file_name)
        Shared.__init__(self, userList)

Objects of class SharedImage can access methods of Image and Shared

Base Overloading Methods

Following table lists some generic functionality that you can override in your own classes -

Consider a class SomeClass

Sr.No Method Description Example
1

__init__ ( self [,args...] )

Constructor (with any optional arguments)

obj = SomeClass(args)

2

__del__( self )

Destructor, deletes an object

del obj

3

__repr__( self )

Evaluable string representation

repr(obj)

4

__str__( self )

Printable string representation

str(obj)

5

__cmp__ ( self, x )

Object comparison

cmp(obj, x)

Overloading Operators

Classes can have methods to overload functionality of operators like + -

This way, behaviour of using operators for objects of these classes can be manipulated

Example

To define the behaviour of + (plus) operator, __add__ method has to be added to a class

#!/usr/bin/python
class Vector:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __str__(self):
        return 'Vector (%d, %d)' %(self.a,self.b)

    def __add__(self,other):
        return Vector(self.a + other.a, self.b + other.b)

v1 = Vector(2,10)
v2 = Vector(5,-2)
print(v1 + v2)

When the above code is executed, it produces the following output :

Vector(7,8)

Data Hiding

An object's attributes may or may not be visible outside the class definition

Attributes and methods can be named with a double underscore prefix, so that these attributes are then not directly visible from its caller or derived class

Example

#!/usr/bin/python
class JustCounter:
    __secretCount =0
    def count(self):
        self.__secretCount += 1
        print(self.__secretCount)

counter = JustCounter()
counter.count()
counter.count()
print counter.__secretCount 

When the above code is executed, it produces the following output :

1
2
Traceback (most recent call last):
   File "test.py", line 12, in <module>
      print counter.__secretCount
AttributeError: JustCounter instance has no attribute '__secretCount' 

Python protects those members by internally changing the name to include the class name

Such attributes can be accessed as object._className__attrName

Replace last line of above example as following, to make it work :

 print counter._JustCounter__secretCount 

It then produces the following output :

1
2
2