Unit V: Object oriented Programming and Recursion Hours: 15
Object Oriented Programming using Python: Encapsulation - Inheritance – Polymorphism.
Recursion: Fundamental Concepts - Recursive Functions - Recursive Problem Solving -
Iteration vs. Recursion - Towers of Hanoi problem.
Encapsulation in Python
Encapsulation is one of the most fundamental concepts in object-oriented
programming (OOP).
This is the concept of wrapping data and methods that work with data in one unit.
This prevents data modification accidentally by limiting access to variables and methods.
An object's method can change a variable's value to prevent accidental changes. These
variables are called private variables.
Encapsulation is demonstrated by a class which encapsulates all data, such as member
functions, variables, and so forth.
Example:
In this example, we create an Employee class by defining employee attributes such as
name and salary as an instance variable and implementing behavior
using work() and show() instance methods.
class Employee:
# constructor
def __init__(self, name, salary, project):
# data members
self.name = name
self.salary = salary
self.project = project
# method
# to display employee's details
def show(self):
# accessing public data member
print("Name: ", self.name, 'Salary:', self.salary)
# method
def work(self):
print(self.name, 'is working on', self.project)
# creating object of a class
emp = Employee('Jessa', 8000, 'NLP')
# calling public method of the class
emp.show()
emp.work()
Output:
Name: Jessa Salary: 8000
Jessa is working on NLP
Access Modifiers in Python
Encapsulation can be achieved by declaring the data members and methods of a class
either as private or protected.
But In Python, we don’t have direct access modifiers like public, private, and
protected. We can achieve this by using single underscore and double underscores.
Access modifiers limit access to the variables and methods of a class. Python provides
three types of access modifiers private, public, and protected.
Public Member: Accessible anywhere from otside oclass.
Private Member: Accessible within the class
Protected Member: Accessible within the class and its sub-classes
Python Inheritance
Inheritance is an important aspect of the object-oriented paradigm. Inheritance
provides code reusability to the program because we can use an existing class to create a new
class instead of creating it from scratch.
In inheritance, the child class acquires the properties and can access all the data
members and functions defined in the parent class.
A child class can also provide its specific implementation to the functions of the
parent class. In this section of the tutorial, we will discuss inheritance in detail.
In python, a derived class can inherit base class by just mentioning the base in the
bracket after the derived class name. Consider the following syntax to inherit a base class into
the derived class.
Syntax
1. class derived-class(base class):
2. <class-suite>
Example 1
1. class Animal:
2. def speak(self):
3. print("Animal Speaking")
4. #child class Dog inherits the base class Animal
5. class Dog(Animal):
6. def bark(self):
7. print("dog barking")
8. d = Dog()
9. d.bark()
10. d.speak()
Output:
dog barking
Animal Speaking
Python Multi-Level inheritance
Multi-Level inheritance is possible in python like other object-oriented languages.
Multi-level inheritance is archived when a derived class inherits another derived class.
There is no limit on the number of levels up to which, the multi-level inheritance is
archived in python.
Syntax
1. class class1:
2. <class-suite>
3. class class2(class1):
4. <class suite>
5. class class3(class2):
6. <class suite>
7. .
Example
1. class Animal:
2. def speak(self):
3. print("Animal Speaking")
4. #The child class Dog inherits the base class Animal
5. class Dog(Animal):
6. def bark(self):
7. print("dog barking")
8. #The child class Dogchild inherits another child class Dog
9. class DogChild(Dog):
10. def eat(self):
11. print("Eating bread...")
12. d = DogChild()
13. d.bark()
14. d.speak()
15. d.eat()
16. Output:
17. dog barking
18. Animal Speaking
19. Eating bread...
Python Multiple inheritance
Python provides us the flexibility to inherit multiple base classes in the child class.
Syntax
1. class Base1:
2. <class-suite>
3.
4. class Base2:
5. <class-suite>
6. .
7. .
8. .
9. class BaseN:
10. <class-suite>
11.
12. class Derived(Base1, Base2, ...... BaseN):
13. <class-suite>
Example
1. class Calculation1:
2. def Summation(self,a,b):
3. return a+b;
4. class Calculation2:
5. def Multiplication(self,a,b):
6. return a*b;
7. class Derived(Calculation1,Calculation2):
8. def Divide(self,a,b):
9. return a/b;
10. d = Derived()
11. print(d.Summation(10,20))
12. print(d.Multiplication(10,20))
13. print(d.Divide(10,20))
14. Output:
15. 30
16. 200
17. 0.5
The issubclass(sub,sup) method
The issubclass(sub, sup) method is used to check the relationships between the specified
classes. It returns true if the first class is the subclass of the second class, and false otherwise.
Consider the following example.
Example
1. class Calculation1:
2. def Summation(self,a,b):
3. return a+b;
4. class Calculation2:
5. def Multiplication(self,a,b):
6. return a*b;
7. class Derived(Calculation1,Calculation2):
8. def Divide(self,a,b):
9. return a/b;
10. d = Derived()
11. print(issubclass(Derived,Calculation2))
12. print(issubclass(Calculation1,Calculation2))
Output:
True
False
The isinstance (obj, class) method
The isinstance() method is used to check the relationship between the objects and
classes. It returns true if the first parameter, i.e., obj is the instance of the second parameter,
i.e., class.
Consider the following example.
Example
1. class Calculation1:
2. def Summation(self,a,b):
3. return a+b;
4. class Calculation2:
5. def Multiplication(self,a,b):
6. return a*b;
7. class Derived(Calculation1,Calculation2):
8. def Divide(self,a,b):
9. return a/b;
10. d = Derived()
11. print(isinstance(d,Derived))
Output:
True
Polymorphism in Python
What is polymorphism? Polymorphism refers to having multiple forms.
Polymorphism is a programming term that refers to the use of the same function name, but
with different signatures, for multiple types.
Example of in-built polymorphic functions:
1. # Python program for demonstrating the in-built poly-morphic functions
2.
3. # len() function is used for a string
4. print (len("Javatpoint"))
5.
6. # len() function is used for a list
7. print (len([110, 210, 130, 321]))
8. Output:
9. 10
10. 4
Polymorphism with Class Methods
Below is an example of how Python can use different types of classes in the same
way. For loops that iterate through multiple objects are created.
Next, call the methods without caring about what class each object belongs to. These
methods are assumed to exist in every class.
Example:
1. class xyz():
2. def websites(self):
3. print("Javatpoint is a website out of many availabe on net.")
4.
5. def topic(self):
6. print("Python is out of many topics about technology on Javatpoint.")
7.
8. def type(self):
9. print("Javatpoint is an developed website.")
10.
11. class PQR():
12. def websites(self):
13. print("Pinkvilla is a website out of many availabe on net. .")
14.
15. def topic(self):
16. print("Celebrities is out of many topics.")
17.
18. def type(self):
19. print("pinkvilla is a developing website.")
20.
21. obj_jtp = xyz()
22. obj_pvl = PQR()
23. for domain in (obj_jtp, obj_pvl):
24. domain.websites()
25. domain.topic()
26. domain.type()
Output:
Javatpoint is a website out of many availabe on net.
Python is out of many topics about technology on Javatpoint.
Javatpoint is an developed website.
Pinkvilla is a website out of many availabe on net.
Celebrities is out of many topics.
pinkvilla is a developing website.
Polymorphism with Inheritance:
Polymorphism allows us to define methods in Python that are the same as methods in
the parent classes. In inheritance, the methods of the parent class are passed to the child class.
It is possible to change a method that a child class has inherited from its parent class.
This is especially useful when the method that was inherited from the parent doesn't
fit the child's class. We re-implement such methods in the child classes. This is Method
Overriding.
1. class Birds:
2. def intro1(self):
3. print("There are multiple types of birds in the world.")
4. def flight1(self):
5. print("Many of these birds can fly but some cannot.")
6.
7. class sparrow1(Birds):
8. def flight1(self):
9. print("Sparrows are the bird which can fly.")
10.
11. class ostrich1(Birds):
12. def flight1(self):
13. print("Ostriches are the birds which cannot fly.")
14.
15. obj_birds = Birds()
16. obj_spr1 = sparrow1()
17. obj_ost1 = ostrich1()
18.
19. obj_birds.intro1()
20. obj_birds.flight1()
21.
22. obj_spr1.intro1()
23. obj_spr1.flight1()
24.
25. obj_ost1.intro1()
26. obj_ost1.flight1()
27. Output:
28. There are multiple types of birds in the world.
29. Many of these birds can fly but some cannot.
30. There are multiple types of birds in the world.
31. Sparrows are the bird which can fly.
32. There are multiple types of birds in the world.
33. Ostriches are the birds which cannot fly.
Polymorphism with a Function and Objects
We can also create functions that can take any object. This allows for polymorphism.
Let's take the following example: let's make a function called "func()", which will take an
object we will call "obj".
Even though we use the name "obj", any object that is instantiated will be able to call
into this function. Let's next to give the function something it can do with the 'obj object
passed to it.
Let's call these three methods websites(), topic(), and type(). Each of them is defined
in the classes' xyz' and 'PQR'.
If we don't already have instantiations of the 'xyz" and 'PQR classes, let us create
them. We can then call their actions using the same function func().
Example:
1. def func(obj):
2. obj.websites()
3. obj.topic()
4. obj.type()
5.
6. obj_jtp = xyz()
7. obj_pvl = PQR()
8.
9. func(obj_jtp)
10. func(obj_pvl)
11. Output:
12. Javatpoint is a website out of many availabe on net.
13. Python is out of many topics about technology on Javatpoint.
14. Javatpoint is a developed website.
15. Pinkvilla is a website out of many availabe on net. .
16. Celebrities is out of many topics.
17. pinkvilla is a developing website.
Recursion in Python
The term Recursion can be defined as the process of defining something in terms of
itself. In simple words, it is a process in which a function calls itself directly or indirectly.
Advantages of using recursion
A complicated function can be split down into smaller sub-problems utilizing recursion.
Sequence creation is simpler through recursion than utilizing any nested iteration.
Recursive functions render the code look simple and effective.
Disadvantages of using recursion
A lot of memory and time is taken through recursive calls which makes it expensive for
use.
Recursive functions are challenging to debug.
The reasoning behind recursion can sometimes be tough to think through.
Syntax:
def func(): <--
|
| (recursive call)
|
func() ----
Example 1: A Fibonacci sequence is the integer sequence of 0, 1, 1, 2, 3, 5, 8….
Program to print the fibonacci series upto n_terms
# Recursive function
def recursive_fibonacci(n):
if n <= 1:
return n
else:
return(recursive_fibonacci(n-1) + recursive_fibonacci(n-2))
n_terms = 10
# check if the number of terms is valid
if n_terms <= 0:
print("Invalid input ! Please input a positive value")
else:
print("Fibonacci series:")
for i in range(n_terms):
print(recursive_fibonacci(i))
Output
Fibonacci series:
0
1
1
2
3
5
8
13
21
34
Python Recursive Function
In Python, we know that a function can call other functions. It is even possible for the
function to call itself.
These types of construct are termed as recursive functions.
The following image shows the working of a recursive function called recurse.
Example of a recursive function
def factorial(x):
"""This is a recursive function
to find the factorial of an integer"""
if x == 1:
return 1
else:
return (x * factorial(x-1))
num = 3
print("The factorial of", num, "is", factorial(num))
Output
The factorial of 3 is 6
Tower of Hanoi Puzzle Using Python
In this tutorial, we will implement the famous Tower of Hanoi puzzle using the
Python program. We will solve this problem by using recursion function.
What is the Tower of Hanoi?
In 1883, the Tower of Hanoi mathematical puzzle was invented by the
French mathematician Edouard Lucas.
The inspiration came from a legend that states - In Ancient Hindu temple, this puzzle
was presented to the young priest. The puzzle is, there are three poles, and 64 disks, and each
disk is smaller than the other.
To solve this problem, move all 64 disks from one of the three poles to another pole
without violating the essential constraints.
The disks can be moved one disk at a time and they should place a smaller disk top of a larger
one.
Other folktale states, when they would solve this puzzle, the temple would smash into
dust, and the world would end.
But it would take a lot of time because to solve this problem 2 64 - 1 moves are
necessary i.e., 18,446,744,073,709,551,615 per second that is equal to 5, 84,942,417,355
years according to the rules.
Rules of the game
The rules of "Tower of Hanoi" are quite simple, but the solution is slightly hard.
There are three rods.
The disks are stacked in the descending order; the largest disk stacked at the bottom
and the smallest one on top.
The task is to transfer the disks from one source rod to another target rod.
The following rule must not be violated
o Only one disk can be moved at a time.
o The most upper disk from one of the rod can be stimulated in move.
o The smaller disk cannot be placed at the lower of the largest disk.
The number of moves can be calculated as 2n - 1.
Solution:
At the beginning of this tutorial, we have mentioned that we will use the recursive
function to find the solution.
Suppose we have three disks on the first rod; we need total 7 moves from the above
formula. The most left rod is called SOURCE, and the rightmost rod is called TARGET.
The middle rod is referred to as an AUX.
The AUX is needed to deposit disks temporarily.
Problem Approach
1. Create a tower_of_hanoi recursive function and pass two arguments: the number of
disks n and the name of the rods such as source, aux, and target.
2. We can define the base case when the number of disks is 1. In this case, simply move
the one disk from the source to target and return.
3. Now, move remaining n-1 disks from source to auxiliary using the target as
the auxiliary.
4. Then, the remaining 1 disk move on the source to target.
5. Move the n-1 disks on the auxiliary to the target using the source as the auxiliary.
Python Program/ Source Code
1. # Creating a recursive function
2. def tower_of_hanoi(disks, source, auxiliary, target):
3. if(disks == 1):
4. print('Move disk 1 from rod {} to rod {}.'.format(source, target))
5. return
6. # function call itself
7. tower_of_hanoi(disks - 1, source, target, auxiliary)
8. print('Move disk {} from rod {} to rod {}.'.format(disks, source, target))
9. tower_of_hanoi(disks - 1, auxiliary, source, target)
10.
11.
12. disks = int(input('Enter the number of disks: '))
13. # We are referring source as A, auxiliary as B, and target as C
14. tower_of_hanoi(disks, 'A', 'B', 'C') # Calling the function
15. Output:
16. Enter the number of disks: 3
17. Move disk 1 from rod A to rod C.
18. Move disk 2 from rod A to rod B.
19. Move disk 1 from rod C to rod B.
20. Move disk 3 from rod A to rod C.
21. Move disk 1 from rod B to rod A.
22. Move disk 2 from rod B to rod C.
23. Move disk 1 from rod A to rod C.