Algorithms and Programming Python 6
Object-Oriented Programming II
Object-Oriented Programming (OOP) is a programming paradigm based on the concept of “objects.” For example, consider a remote-controlled toy car: the car itself is the object, and the remote control is the device that controls it. You can move the RC car forward, backward, left, and right using the remote, illustrating the basic concept of OOP. Python supports Object-Oriented Programming through features like functions and classes.
Class
A class is a prototype, blueprint, or design that defines the variables and methods for specific objects. It serves to encapsulate the content of the program that will be executed, containing attributes/data types and methods to carry out a program. In Python, a class is defined using the keyword class, followed by the name of the class, like this: class class_name. Calling a class is similar to calling a function/method in a program by invoking the class name along with its parameters. Typically, a class contains many methods/functions that represent the properties of that class.
Classes can take various forms in different programming languages, such as abstract classes, data classes, and more. A class can also relate to other classes in a relationship known as inheritance, where a Parent Class (Base Class) has a Child Class (Derived Class) that inherits the same properties and variables.
For example, consider a car class: the car has attributes like engine, wheels, battery, etc. The car is a class, while the engine, wheels, battery, etc., are functionalities.
Important Aspects of Declaring a Class:
- Initialization Function
- Self Parameter
Initialization Function
This is a mandatory function that must be initialized when creating and declaring a class. It is used to add arguments and store parameters within the class.
Self Parameter
This is a variable that can only be used within the class declaration.
Simple Class Declaration Example:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class Employee:
"Common base class for all employees"
empCount = 0
def __init__(self, name="Employee", salary=5000):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print("Total Employees: %d" % Employee.empCount)
def printEmployee(self):
print("Name:", self.name, "\nSalary:", self.salary)
employee1 = Employee("Azhar", 5000)
employee1.printEmployee()
employee1.displayCount()
employee2 = Employee("Gerald", 4000)
employee2.printEmployee()
employee2.displayCount()
Getter Method
This method retrieves data from the class. It is typically used when there is data that needs to be exported or accessed from the class.
You can use a getter method by creating a function that returns values in the class declaration.
Setter Method
This method changes data within the class. Sometimes setters are needed when dealing with immutable data or data that requires modification.
You can use the setter method similarly to declaring the init function in the class.
Example of Getter and Setter Methods:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47class Employee:
"Common base class for all employees"
empCount = 0
def __init__(self, name="Employee", salary=5000):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print("Total Employees: %d" % Employee.empCount)
def printEmployee(self):
print("Name:", self.name, "\nSalary:", self.salary)
# Getter Method Declaration
def getName(self):
return self.name
def getSalary(self):
return self.salary
# Setter Method Declaration
def setName(self, name):
self.name = name
def setSalary(self, salary):
self.salary = salary
employee1 = Employee()
employee1.printEmployee()
employee1.displayCount()
# Example of Getter Implementation
employeeName = employee1.getName()
print("Employee's name is", employeeName)
# Example of Setter Implementation
employee1.setName("Azhar")
employee1.setSalary(10000)
employee1.printEmployee()
employee2 = Employee("Gerald", 4000)
employee2.printEmployee()
employee2.displayCount()
The Modern Pythonic Way: @property Decorator
The manual getName()/setName() pattern shown above is common in languages like Java or C#, but it is not the idiomatic style in modern Python. Python code today typically uses the built-in @property decorator instead, so that a “getter” and “setter” can be accessed like a normal attribute (employee.salary) instead of a method call (employee.getSalary()), while still allowing validation logic behind the scenes:
1 | class Employee: |
dataclass (Modern Standard for Simple Data-Holding Classes)
For classes whose main purpose is to store data (like Employee or Student), modern Python offers the @dataclass decorator (from the built-in dataclasses module), which automatically generates __init__, a readable __repr__, and comparison methods — removing a lot of boilerplate code:
1 | from dataclasses import dataclass |
Both @property and @dataclass are considered current industry best practice and are commonly seen in professional Python codebases, though understanding the classic __init__/getter/setter pattern above is still essential, since it explains what these modern tools are doing under the hood.
Inheritance
Inheritance was mentioned briefly at the start of this module (“a Parent Class has a Child Class that inherits the same properties”) but was never demonstrated in code. Inheritance is one of the four core pillars of OOP, and lets a new class reuse the attributes and methods of an existing class:
1 | # Parent Class (Base Class) |
Dog(Animal) means Dog inherits everything from Animal. Both Dog and Cat reuse the eat() method without rewriting it, while each provides its own version of make_sound(). This avoids code duplication — the same core benefit functions gave us earlier, now applied to classes.
Polymorphism
Polymorphism (“many forms”) means objects of different classes can be used through the same interface, each responding in its own way. Using the Dog and Cat classes above:
1 | animals = [Dog("Rex"), Cat("Milo"), Dog("Buddy")] |
Output:1
2
3Rex says: Woof!
Milo says: Meow!
Buddy says: Woof!
Even though animal.make_sound() is called the same way for every item, Python automatically runs the correct version depending on the actual object type (Dog or Cat). This is polymorphism in practice, and it’s what makes code like this loop possible without needing if isinstance(animal, Dog): ... checks everywhere.
Encapsulation (Naming Clarification, Added)
The @property example shown earlier in this module (using self._salary with a leading underscore) is actually an OOP concept called Encapsulation — bundling data and the methods that protect/control access to it inside a class. Python doesn’t have true “private” variables like Java (private int salary;); instead it uses a naming convention:
self.name— public, accessible directlyself._name— “protected” by convention only (a single underscore signals “internal use,” but Python does not enforce it)self.__name— “private” (double underscore triggers Python’s name-mangling, making it harder — though not impossible — to access from outside the class)
Abstraction
The last of the four pillars is Abstraction: exposing only the relevant, essential features of an object while hiding the complicated implementation details behind a simple interface. As a real-world analogy, when you drive a car, you only interact with the steering wheel, pedals, and gear stick — you don’t need to know how the engine, fuel injection, or transmission actually work internally to be able to drive it.
In Python, Abstraction is commonly implemented using the built-in abc (Abstract Base Class) module. An abstract class cannot be instantiated directly — it exists only to be inherited from, and it forces every child class to implement certain methods, using the @abstractmethod decorator:
1 | from abc import ABC, abstractmethod |
Trying to create Shape() directly raises a TypeError, because Shape is only meant to define what every shape must be able to do (area() and perimeter()), not how — the “how” is left entirely to each concrete child class like Rectangle and Circle. Notice how this reuses the same Shape/Rectangle/Circle idea from the Polymorphism example above: Abstraction is what guarantees, at the class-design level, that every shape subclass will always provide an area() method, instead of just relying on convention.
Encapsulation, Inheritance, Polymorphism, and Abstraction (hiding internal complexity) together form the four pillars of Object-Oriented Programming.
Exercise
Exercise 1
Create a program that implements a class named Student with methods to display the biodata of the student entered by the user.
Exercise 2 (Inheritance & Polymorphism)
Create a parent class named Shape with a method area() that returns 0. Create two child classes, Rectangle and Circle, that each override area() with the correct formula. Store several shape objects in a list and loop through them, printing each shape’s area using the same area() method call (polymorphism).
Exercise 3 (Abstraction)
Create an abstract class named PaymentMethod with an abstract method pay(amount). Create two concrete child classes, CreditCard and EBanking, that each implement pay(amount) with their own printed message (e.g., “Paid $50 using Credit Card”). Instantiate both classes, store them in a list, and loop through the list calling pay() on each, similar to Exercise 2 above.
Exercise 4
Create a class that implements getter and setter methods, utilizing branching and looping as in the previous exercise. The program should accept user input for variable declarations and store them in a class, allowing manipulation and modification based on user input. The data can be displayed using the getter and setter methods.
Example Output:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85===== OOP Program =====
1. Declare Object
2. Display Object
3. Change Object Value
4. Delete Object
5. Exit Program
Enter Your Choice (1/2/3/4/5): 2 (Input by User)
Name: None
Score: None
===== OOP Program =====
1. Declare Object
2. Display Object
3. Change Object Value
4. Delete Object
5. Exit Program
Enter Your Choice (1/2/3/4/5): 1 (Input by User)
Enter Your Name: ARZ (Input by User)
Enter Your Score: 95 (Input by User)
Data Successfully Added
===== OOP Program =====
1. Declare Object
2. Display Object
3. Change Object Value
4. Delete Object
5. Exit Program
Enter Your Choice (1/2/3/4/5): 2 (Input by User)
Name: ARZ
Score: 95
===== OOP Program =====
1. Declare Object
2. Display Object
3. Change Object Value
4. Delete Object
5. Exit Program
Enter Your Choice (1/2/3/4/5): 3 (Input by User)
What would you like to change (Name/Score): Score (Input by User)
Enter New Score: 100 (Input by User)
Score Data Successfully Changed
===== OOP Program =====
1. Declare Object
2. Display Object
3. Change Object Value
4. Delete Object
5. Exit Program
Enter Your Choice (1/2/3/4/5): 2 (Input by User)
Name: ARZ
Score: 100
===== OOP Program =====
1. Declare Object
2. Display Object
3. Change Object Value
4. Delete Object
5. Exit Program
Enter Your Choice (1/2/3/4/5): 4 (Input by User)
Data Successfully Deleted
===== OOP Program =====
1. Declare Object
2. Display Object
3. Change Object Value
4. Delete Object
5. Exit Program
Enter Your Choice (1/2/3/4/5): 2 (Input by User)
Name: None
Score: None
===== OOP Program =====
1. Declare Object
2. Display Object
3. Change Object Value
4. Delete Object
5. Exit Program
Enter Your Choice (1/2/3/4/5): 5 (Input by User)
Thank you for using my program.


