Unit 3: Object Oriented Programming Using Python — Long Questions
12th Class Computer Science · Unit 3: Object Oriented Programming Using Python
In OOP, a class is a blueprint or template that defines the attributes (properties) and methods (behaviors) that describe an entity, but it does not itself contain real data. An object is an instance of a class created from that blueprint; it holds actual values for the attributes defined by the class and can use the class's methods. Classes and objects together allow programmers to model real-world entities in code and keep related data and functionality organized in one place.
For example
class Student:
def _init_(self, name):
self.name = name
def display(self):
print("Student Name:", self.name)
# Creating objects
object1 = Student("Ali")
object2 = Student("Ahmed")
# Using objects
object1.display()
object2.display()
Here, Student is the class (blueprint); object1 and object2 are two separate objects created from it, each holding its own data ("Ali" and "Ahmed"). The _init_ method initializes each object's name attribute when it is created, and display() is a method shared by all objects of the class.
Encapsulation is the OOP concept of bundling data (variables) and methods (functions) into a single unit, a class, and restricting direct access to that data. Unlike languages such as Java or C++, Python does not have strict private/protected keywords; instead it uses naming conventions to control access, with three levels:
• Public members – accessible from anywhere, written as self.attributename (the default in Python).
• Protected members – intended for use within the class and its subclasses, written with a single underscore, self.attributename (a convention, not an enforced restriction).
• Private members – highly restricted, written with a double underscore, self._attributename; Python applies name mangling to prevent accidental outside access.
Encapsulation is important because it protects data from unwanted access, improves security, makes code easier to manage, and allows controlled modification. For example, in a BankAccount class the balance is stored as a private variable self._balance and can only be changed through deposit() and withdraw() methods, and read through getbalance() — direct access like account._balance fails:
class BankAccount:
def _init_(self, balance):
self._balance = balance # Private variable
def deposit(self, amount):
self._balance += amount
def withdraw(self, amount):
if amount <= self._balance:
self._balance -= amount
else:
print("Insufficient balance")
def getbalance(self):
return self._balance
Inheritance lets a class (child/subclass) take properties and methods from another class (parent/superclass), and the child class can add new features or modify (override) the parent's features. There are three types of inheritance covered:
1. Single Inheritance – a child class inherits from exactly one parent class.
class Animal:
def _init_(self, name):
self.name = name
def eat(self):
print(f"{self.name} is eating.")
class Dog(Animal):
def bark(self):
print(f"{self.name} says Woof!")
mydog = Dog("Buddy")
mydog.eat() # inherited from Animal
mydog.bark() # defined in Dog
2. Multiple Inheritance – a single child class inherits from more than one parent class, combining behaviors from each, e.g. class Child(Father, Mother): can call both skill1() from Father and skill2() from Mother.
3. Multilevel Inheritance – a class inherits from a class that is itself derived from another class, forming a chain (Grandparent → Parent → Child), e.g. class ElectricCar(Car) where class Car(Vehicle); ElectricCar objects can access methods from Vehicle, Car, and ElectricCar all at once.
A child class can also override a parent's method with its own implementation, and use super() to still call the parent's original version if needed.
• Code reuse: a child class automatically gets the attributes and methods of its parent class without rewriting them.
• Reduced redundancy: common functionality is written once in the parent class instead of being duplicated in every related class.
• Easier extension: new programs or features can be built by extending existing classes (adding or overriding methods) rather than rewriting existing code from scratch.
• Supports modularity and maintainability: changes made in the parent class are automatically available to all child classes, making programs easier to manage and update.
• Flexibility through method overriding: a child class can customize inherited behavior for its own specific needs while still being able to call the parent's version using super().
Polymorphism means "many forms" it is the ability of the same method, function, or operator to behave differently depending on the object it is working with. It mainly includes two types:
1. Compile-time Polymorphism (Method Overloading): deciding which operation to run is normally done at compile time in languages like Java or C++. Python does not support true signature-based method overloading since it is dynamically typed, but similar behavior is achieved using default arguments and variable-length arguments (*args, **kwargs):
class Calculator:
def multiply(self, a=1, b=1, *args):
result = a * b
for num in args:
result *= num
return result
calc = Calculator()
print(calc.multiply()) # 1
print(calc.multiply(4)) # 4
print(calc.multiply(2, 3)) # 6
print(calc.multiply(2, 3, 4)) # 24
2. Runtime Polymorphism (Method Overriding): the behavior of a method is decided while the program runs, based on the actual object calling it, because a child class overrides a method defined in the parent class:
class Animal:
def sound(self):
return "Some generic sound"
class Dog(Animal):
def sound(self):
return "Bark"
class Cat(Animal):
def sound(self):
return "Meow"
animals = [Dog(), Cat(), Animal()]
for animal in animals:
print(animal.sound()) # Bark, Meow, Some generic sound
Polymorphism enhances flexibility because the same method call (sound(), processPayment()) works correctly for many different object types, so new object types can be added later without changing the code that calls the method.
Encapsulation improves data security by hiding an object's internal data and exposing only controlled ways to interact with it. By declaring an attribute as private using a double underscore (e.g., self._balance), Python applies name mangling so the attribute cannot be accessed directly from outside the class (account._balance raises an error). Instead, the data can only be read or changed through the class's own public methods, such as deposit(), withdraw(), and getbalance(). These methods can include validation logic — for instance, withdraw() checks 'if amount <= self._balance' before reducing the balance and prints "Insufficient balance" otherwise — preventing invalid or unauthorized changes to the data. This way, the internal state of the object stays protected and consistent at all times.
Together, these three OOP concepts make software more modular, reusable, and easier to maintain:
• Encapsulation bundles data and methods into classes and restricts direct access to data, which protects data integrity and keeps each class's internal details hidden, so other parts of the program cannot interfere with it unexpectedly.
• Inheritance lets new classes reuse and extend the attributes and methods of existing classes instead of duplicating code, so a change in a parent class automatically benefits all its child classes, reducing redundancy and making the system easier to extend.
• Polymorphism allows the same method name to behave appropriately for different object types (through overriding or flexible arguments), so calling code can work with many different classes through one common interface, without needing to know each object's exact type.
Because code is divided into classes (modularity), can be reused in multiple programs (reusability), and changes in one class do not affect the whole system (easier maintenance), this combination results in organized, scalable, and maintainable software that is also easier for teams to understand and collaborate on.
• Definition: A class is a blueprint or template that defines the attributes and methods of an entity; an object is an instance of a class that represents a real, specific entity.
• Data: A class itself does not hold actual data values, only the definition of what data (attributes) will look like; an object holds actual values for those attributes (e.g., name = "Ali").
• Number: Only one class definition is needed, but many different objects can be created from the same class (e.g., object1 = Student("Ali"), object2 = Student("Ahmed")), and each object keeps its own independent copy of the data.
• Creation: A class is defined once using the class keyword; objects are created afterward by calling the class as if it were a function, which triggers _init_ to set up that object's data.
• Usage: Methods and behavior are defined in the class, but they are invoked on objects (e.g., object1.display()), which use the object's own stored data when the method runs.