Object-Oriented Programming Concepts
Programming paradigms represent different approaches to problem-solving using computers. Two primary paradigms exist: procedural and object-oriented programming. Python supports both approaches.
Procedural Programing
This paradigm follows a top-down approach with step-by-step refinement:
- Problems are broken into sequential steps
- Complex steps can be further decomposed
- Functions serve as modular building blocks
- Core concept: functions as primary organizational units
Object-Oriented Programming
This approach models real-world entities as objects with attributes and behaviors.
Class Definition
Python supports both classic and new-style classes:
class ClassicClass:
pass
class NewStyleClass(object):
pass
Classes follow naming conventions (typically PascalCase) and contain attributes and methods.
class Individual(object):
def consume(self):
print('eating')
def move(self):
print('running')
Object Instantiation
Classes are abstract templates that become concrete objects through instantiation:
class Individual(object):
def consume(self):
print('eating')
def move(self):
print('running')
person = Individual()
person.consume() # eating
Objects occupy memory space and inherit all class attributes and methods.
Instance Attributes and Methods
The self Parameter
The self parameter represents the instance itself within class methods:
class Individual(object):
def consume(self):
print('eating')
def introduce(self):
print(self)
person = Individual()
print(person) # <__main__.Individual object at 0x...>
person.introduce() # <__main__.Individual object at 0x...>
Adding and Accessing Attributes
Attributes can be added externally or internally:
class Individual(object):
def consume(self):
print('eating')
def display_info(self):
print(f'Name: {self.name}')
print(f'Age: {self.age}')
# External attribute assignment
person = Individual()
person.name = 'Alex'
person.age = 25
person.display_info() # Name: Alex, Age: 25
Class Attributes
Shared attributes across all instances:
class Individual(object):
population = 0
def __init__(self, name, age):
self.name = name
self.age = age
Individual.population += 1
person1 = Individual('John', 30)
person2 = Individual('Jane', 28)
print(Individual.population) # 2
Class Methods
Methods that operate on class attributes:
class Utility(object):
count = 0
def __init__(self, name):
self.name = name
Utility.count += 1
@classmethod
def get_count(cls):
return f'Total instances: {cls.count}'
utility = Utility('hammer')
print(Utility.get_count()) # Total instances: 1
Static Methods
Utility methods that don't require instance or class access:
class StudentSystem(object):
@staticmethod
def show_menu():
print('-' * 40)
print('Student Management System v1.0')
print('[1] Add Student')
print('[2] Remove Student')
print('[3] Modify Student')
print('[4] Search Student')
print('-' * 40)
StudentSystem.show_menu()
Magic Methods
__init__ Constructor
Initializes object attributes during instantiation:
class Person():
def __init__(self, name, age):
self.name = name
self.age = age
individual = Person('Alice', 22)
print(individual.name) # Alice
print(individual.age) # 22
__str__ String Representation
Controls object string output:
class Vehicle():
def __init__(self, brand, model, color):
self.brand = brand
self.model = model
self.color = color
def __str__(self):
return f'Brand: {self.brand}, Model: {self.model}, Color: {self.color}'
vehicle = Vehicle('BMW', 'X5', 'black')
print(vehicle) # Brand: BMW, Model: X5, Color: black
__del__ Destructor
Handles cleanup when objects are deleted:
class Person():
def __init__(self, name, age):
self.name = name
self.age = age
def __del__(self):
print(f'{self} object deleted')
person = Person('Sarah', 35)
del person # <__main__.Person object at 0x...> object deleted
Practical Examples
Grade Reporting System
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def report_grade(self):
if self.score >= 90:
print(f'{self.name}: {self.score} - Excellent')
elif 80 <= self.score < 90:
print(f'{self.name}: {self.score} - Good')
elif 70 <= self.score < 80:
print(f'{self.name}: {self.score} - Average')
elif 60 <= self.score < 70:
print(f'{self.name}: {self.score} - Pass')
else:
print(f'{self.name}: {self.score} - Fail')
student = Student('Tom', 85)
student.report_grade() # Tom: 85 - Good
Fitness Tracker
class Person(object):
def __init__(self, name, weight):
self.name = name
self.weight = weight
def exercise(self):
self.weight -= 0.1
def eat(self):
self.weight += 0.2
def __str__(self):
return f'{self.name} weighs {self.weight:.2f} kg'
athlete = Person('Mike', 75.0)
athlete.exercise()
print(athlete) # Mike weighs 74.90 kg
athlete.eat()
print(athlete) # Mike weighs 75.10 kg
Furniture Arrangement
class Residence(object):
def __init__(self, location, space):
self.location = location
self.space = space
self.furniture = []
def add_item(self, item):
required_space = item.get_area()
if self.space >= required_space:
self.furniture.append(item)
self.space -= required_space
print('Furniture placed successfully')
else:
print('Insufficient space for furniture')
def __str__(self):
info = f'Residence at {self.location}, remaining space: {self.space}'
if self.furniture:
info += ', furniture: '
info += ', '.join([item.get_name() for item in self.furniture])
return info
class Furniture(object):
def __init__(self, name, area):
self.__name = name
self.__area = area
def get_area(self):
return self.__area
def get_name(self):
return self.__name
bed = Furniture('Mattress', 5)
table = Furniture('Desk', 3)
home = Residence('Downtown', 50)
home.add_item(bed)
home.add_item(table)
print(home) # Residence at Downtown, remaining space: 42, furniture: Mattress, Desk
Core OOP Principles
Encapsulation
Bundling data and methods while controlling access:
class Person(object):
def __init__(self, name):
self.__name = name
self.__age = 18
def get_name(self):
return self.__name
def get_age(self):
return self.__age
person = Person('Emma')
print(person.get_age()) # 18
Private attributes use double underscores prefix.
Inheritance
Creating new classes based on existing ones:
class Animal(object):
def eat(self):
print('consuming food')
def move(self):
print('moving')
class Canine(Animal):
pass
dog = Canine()
dog.eat() # consuming food
dog.move() # moving
Single Inheritance
class Vehicle(object):
def __init__(self, brand, model):
self.brand = brand
self.model = model
def drive(self):
print('driving')
class SportsCar(Vehicle):
pass
car = SportsCar('Ferrari', 'F40')
print(car.brand) # Ferrari
print(car.model) # F40
car.drive() # driving
Multiple Inheritance
class ElectricEngine(object):
def power_electric(self):
print('electric powered')
class GasEngine(object):
def power_gas(self):
print('gas powered')
class HybridVehicle(ElectricEngine, GasEngine):
pass
hybrid = HybridVehicle()
hybrid.power_electric() # electric powered
hybrid.power_gas() # gas powered
Method Overriding
class Animal(object):
def communicate(self):
print('making sounds')
class Dog(Animal):
def communicate(self):
print('barking')
class Cat(Animal):
def communicate(self):
print('meowing')
dog = Dog()
cat = Cat()
dog.communicate() # barking
cat.communicate() # meowing
Super Function
Accessing parent clas methods:
class Vehicle(object):
def __init__(self, brand, model, color):
self.brand = brand
self.model = model
self.color = color
def operate(self):
print('vehicle operating')
class ElectricVehicle(Vehicle):
def __init__(self, brand, model, color, battery):
super().__init__(brand, model, color)
self.battery = battery
def operate(self):
super().operate()
print('electric operation')
tesla = ElectricVehicle('Tesla', 'Model 3', 'white', 75)
print(tesla.brand, tesla.battery) # Tesla 75
tesla.operate() # vehicle operating
# electric operation
Polymorphism
Same interface with different implementations:
class Beverage(object):
def prepare(self):
pass
class Coffee(Beverage):
def prepare(self):
print('brewing coffee')
class Tea(Beverage):
def prepare(self):
print('steeping tea')
def serve_drink(beverage):
beverage.prepare()
coffee = Coffee()
teacup = Tea()
serve_drink(coffee) # brewing coffee
serve_drink(teacup) # steeping tea
Method Resolution Order
Determines inheritance priority in multiple inheritance:
class ElectricEngine(object):
def start(self):
print('electric engine starting')
class GasEngine(object):
def start(self):
print('gas engine starting')
class HybridVehicle(ElectricEngine, GasEngine):
pass
print(HybridVehicle.__mro__)
# (<class '__main__.HybridVehicle'>, <class '__main__.ElectricEngine'>,
# <class '__main__.GasEngine'>, <class 'object'>)
Object to Dictionary Conversion
Convert object attributes to dictionary format:
class Example(object):
class_attr = 0
def __init__(self):
self.instance_attr = 1
obj = Example()
print(obj.__dict__) # {'instance_attr': 1}
Student Management System Implementation
Main Application
from student_manager import StudentManager
if __name__ == '__main__':
manager = StudentManager()
manager.launch()
Student Class
class Student(object):
def __init__(self, name, age, phone):
self.name = name
self.age = age
self.phone = phone
def __str__(self):
return f'Name: {self.name}, Age: {self.age}, Phone: {self.phone}'
Manager Class
from student import Student
class StudentManager(object):
def __init__(self):
self.students = []
@staticmethod
def display_menu():
print('-' * 40)
print('Student Management System v2.0')
print('[1] Add Student')
print('[2] Delete Student')
print('[3] Update Student')
print('[4] Search Student')
print('[5] List All Students')
print('[6] Save Data')
print('[0] Exit')
print('-' * 40)
def add_student(self):
name = input('Enter student name: ')
age = input('Enter student age: ')
phone = input('Enter student phone: ')
student = Student(name, age, phone)
self.students.append(student)
print(student)
print('Student added successfully')
def delete_student(self):
name = input('Enter name to delete: ')
for student in self.students:
if student.name == name:
self.students.remove(student)
print(f'{name} removed')
return
print(f'{name} not found')
def update_student(self):
name = input('Enter name to update: ')
for student in self.students:
if student.name == name:
student.name = input('New name: ')
student.age = input('New age: ')
student.phone = input('New phone: ')
print('Update successful')
return
print(f'{name} not found')
def search_student(self):
name = input('Enter name to search: ')
for student in self.students:
if student.name == name:
print(student)
return
print(f'{name} not found')
def list_students(self):
if self.students:
for student in self.students:
print(student)
else:
print('No students available')
def save_data(self):
with open('./students.txt', 'w', encoding='utf-8') as file:
file.write(str([student.__dict__ for student in self.students]))
print('Data saved')
def load_data(self):
try:
with open('./students.txt', 'r', encoding='utf-8') as file:
content = file.read()
if content:
data = eval(content)
self.students = [Student(item['name'], item['age'], item['phone'])
for item in data]
except FileNotFoundError:
pass
def launch(self):
self.load_data()
while True:
StudentManager.display_menu()
choice = int(input('Select option: '))
if choice == 1:
self.add_student()
elif choice == 2:
self.delete_student()
elif choice == 3:
self.update_student()
elif choice == 4:
self.search_student()
elif choice == 5:
self.list_students()
elif choice == 6:
self.save_data()
elif choice == 0:
print('Exiting system')
break
else:
print('Invalid option')