Object Oriented Programming - Part II

( 3 users )

In this chapter, we are going to learn about how to implement the advance concept of object oriented programming in Python. We are going to cover - Inheritance, Multiple Inheritance, Method Overloading, Method Overriding and making variables private. Please note that this chapter is in continuation to previous chapter.

Inheritance in Python

In object oriented programming, Inheritance is a way to reuse data members and function members of a class (Parent class or Base class) into another class (Child class or Derived class). Its a real world concept where a Child gets some common properties from its Parent.

To inherit a parent class we use the below format.


class ChildClassName(ParentClassName):
    <statement-1>
    .
    .
    .
    <statement-N>
		

Lets consider an example


class Logger:
	
	def __init__(self, name):
		self.name = name
		
	def write(self, message):
		print(f"\n[Writing to {self.name}] - {message}")

class FileLogger(Logger):
	
	def __init__(self, name):
		Logger.__init__(self, name)
	
class DBLogger(Logger):

	def __init__(self, name):
		Logger.__init__(self, name)

logMessage = "This is a message"
fileLogger = FileLogger("File")
dbLogger = DBLogger("Database")

fileLogger.write(logMessage)
dbLogger.write(logMessage)
		

Here, in the example above, we have a parent class Logger and two child classes FileLogger and DBLogger. The parent class Logger contains a method write which is inherited in the child classes. Then we have created instance of both child classes. Since write method is inherited from parent class, so it is available to child classes and we can call this method by the child class instances (fileLogger and dbLogger).

The child constructor must call the parent constructor (In above example like Logger.__init__(self, name)) to initialize the parent members which the parent constructor is expecting to be initialized.

Multiple Inheritance

Just like inheritance, if a child class is inherited from two or more parent class, then we call this inheritance as multiple inheritance. All the public variables and methods of all parent class are available in the child class. Here is an example below.


class Employee:
	def __init__(self, empCode):
		self.empCode = empCode
	
	def isValidEmployee(self):
		return str(self.empCode).startswith("ES-")


class Student:
	def __init__(self, idNumber):
		self.idNumber = idNumber
	
	def isValidStudent(self):
		return str(self.idNumber).startswith("SA-")

class EmployeeAndStudent(Employee, Student):
	def __init__(self, empCode, idNumber):
		Employee.__init__(self, empCode)
		Student.__init__(self, idNumber)
	
	def isValid(self):
		return Employee.isValidEmployee(self) and Student.isValidStudent(self)

alice = EmployeeAndStudent("ES-004", "SA-009")
if(alice.isValid()):
	print("Alice is a valid student and employee")
else:
	print("Alice is not a valid student or employee")

bob = EmployeeAndStudent("ES-004", "SB-009")
if(bob.isValid()):
	print("Bob is a valid student and employee")
else:
	print("Bob is not a valid student or employee")
		

In the above example, the child class EmployeeAndStudent is inherited by two parent classes (Employee and Student). Hence the isValidEmployee() and isValidStudent() are available in the child class. We are calling both methods inside the child class method isValid().

Method Overloading

Method overloading in Python is achieved by passing default values in the in the argument list. Passing default values in arguments was already covered in the chapter - Functions and lambda expressions.

Lets see an example how we can implemented method overloading with this feature.


class Box:

	def __init__(self, name):
		self.name = name
		
	def setDimentions(self, width = 10, length = 10, height = 10):
		self.width = width
		self.length = length
		self.height = height
	
	def printBox(self):
		print(f"{self.name} dimensions : Width - {self.width}, Length - {self.length}, Height - {self.height}")
		
box1 = Box("Box 1")
box1.setDimentions()

box2 = Box("Box 2")
box2.setDimentions(20)

box3 = Box("Box 3")
box3.setDimentions(20, 30)

box4 = Box("Box 4")
box4.setDimentions(20, 30, 40)

box5 = Box("Box 5")
box5.setDimentions(length=25)

box1.printBox()
box2.printBox()
box3.printBox()
box4.printBox()
box5.printBox()
		

Method Overriding

In object oriented programming, method overriding is a way in which a child class provides its own method definition instead of using the parent's method definition. This means that child class has overridden the method of the base class.

Lets see this by extending our previous Logger class example.


class Logger:
	
	def __init__(self, name):
		self.name = name
		
	def write(self, message):
		print(f"\n[Writing to {self.name}] - {message}")

class FileLogger(Logger):
	
	def __init__(self, name, filePath):
		self.name = name
		self.filePath = filePath
	
	def write(self, message):
		print(f"\n[Writing to {self.name} -> {self.filePath}] - {message}")
	
class DBLogger(Logger):

	def __init__(self, name):
		self.name = name

logMessage = "This is a message"
fileLogger = FileLogger("File", "/logs/service.logs")
dbLogger = DBLogger("Database")

fileLogger.write(logMessage)
dbLogger.write(logMessage)
		

In the above example, we have overridden the base class method write into one child class FileLogger. Hence, when calling the write method on FileLogger class instance, the FileLogger write method will be invoked instead of the Logger write method.

Private data members

This is a fundamental requirement of any class that it should not expose its data members to be manipulated directly outside the class and therefore there should be some way to hide the data members or making then private. In python we can make a class or instance member private by prefixing __ (double underscore) before a variable name. Lets see this with an example.


class Employee:

  def __init__(self, name):
    self.__name = name
  
  def getName(self):
    return self.__name

alice = Employee("Alice")
name = alice.getName()
print(name)
		

In above example, if we try to access alice.__name then Python interpreter will give the error - AttributeError: 'Employee' object has no attribute '__name'

Python jupyter notebook for code examples

Access Jupyter notebook for this chapter here:

Jupyter Notebook - OOP inheritance, overloading and overriding

To Do

* Note : These actions will be locked once done and hence can not be reverted.

1. Track your progress [Earn 200 points]

2. Provide your ratings to this chapter [Earn 100 points]

0
Object Oriented Programming - Part I
Exception Handling
Note : At the end of this chapter, there is a ToDo section where you have to mark this chapter as completed to record your progress.