Introduction to Object-Oriented Programming (OOP) and its Use in Python

Lesson Overview

This lesson introduces Object-Oriented Programming (OOP) as a programming standard that organizes code by grouping related data and behaviour into objects. It explains why OOP is valuable in Python for building scalable, reusable, and maintainable software, and lays the foundation for understanding core OOP concepts.

Lesson Content

Student Portfolio

Let’s begin with a simple example: a student's portfolio or bio-data. What kind of information do you think should be captured for each student? Usually, it includes details like name, age, class, and roll number.

How would you represent this student data in a python programming? A general approach is to use dictionaries where each key represents a field (like "name") and the value holds the data ("Amit").

student1 = {"name": "Krishna", "age": 16, "class": "10th", "roll_number": 21, "type" : 'student' }
student2 = {"name": "Radha", "age": 15, "class": "10th", "roll_number": 22, "type" : 'student' }

This works well for small sets of data. But what if the school size grows and you have hundreds or thousands of students? Your program will now have many dictionaries, and managing all this data becomes tedious.

Adding New Keys

Suppose the school wants to add new fields such as total fees or concessions. You now have to go through every single dictionary and add these new keys. you might write functions to achieve the same objective

def add_fees_info(student):         # 'student' is of dict type
    student["total_fees"] = 50000
    student["concessions"] = 5000
student1 = add_fees_info(student1 ) # This will add the two new keys to the existing dictionary
#Output : {"name": "Krishna", "age": 16, "class": "10th", "roll_number": 21, "type" : 'student', "total_fees" : 50000, "concessions" : 5000 }

But as the program grows, remembering to call this function on every student dictionary and this may lead to mistakes, inconsistent data, and increasing complexity.

Adding Behaviour - The Full Name Example

Imagine you want to display the full name of the student but with a prefix, such as "Student : ". You can write a function:

def full_name(student):                      # 'student' is of dict type
    return 'Student : '+ student["name"] 

So far so good. Now imagine the school needs a similar portfolio for teachers. For teachers, a similar approach can be followed by creating another dictionary containing similar but possibly different fields such as name, age, subject, and experience. This reflects their unique data needs while maintaining a similar structure to student data.

teacher1 = {"name": "Prasad", "age": 35, "subject": "Socail", "id": 2122, "type" : 'teacher' }
teacher2 = {"name": "Venkat", "age": 42, "subject": "Maths", "id": 2234, "type" : 'teacher' }

For teachers, the full name prefix should be "Teacher : ". If you reuse the same function, you might need to add an if-else condition inside:

def full_name(person):                             # 'person' is a dictionary that represents either stundent or teacher
    if person['type'] == 'teacher' :
        return "Teacher : " + person["name"] 
    else:
        return "Student : " + person["name"] 

Where Does Complexity Hide?

Although this approach solves the immediate problem, the function quickly becomes cluttered and complicated as more roles like parents, staff, or administrators are added, each with their own behaviours. This forces repeated modifications to existing, working code, increasing the chance of introducing errors and reducing code clarity. Every time a new role is introduced, the same function requires editing, making the program tightly coupled, harder to maintain, and more bug-prone.

Tags: object-oriented programming python python-oops

💬 Comments (0)

No comments yet. Be the first to share your thoughts!