Object Oriented Programming
✕1. 🧱 Introduction to OOP
- OOP stands for Object-Oriented Programming. Imagine you are creating a FIFA-style football game. If we only use normal functions, the code can become messy because we need to manage many things: - Players - Teams - Matches - Scores - Player positions - Player actions OOP helps us organize this kind of complex program in a cleaner way. In OOP, we create classes and objects. A class is like a blueprint. An object is an actual thing created from that blueprint. Example: Player class ➜ Blueprint for players Messi object ➜ One actual player Ronaldo object ➜ Another actual player For a FIFA-style game, we can create classes like: - Player - Team - Match - Stadium - Scoreboard
- A class defines what an object should have and what it can do. An object is created from a class. Example: Class: Player Objects: messi, ronaldo, mbappe The Player class can define common details for every player. Each player object can have its own values.
- Objects usually have attributes and methods. Attributes are data related to an object. Methods are actions that an object can perform. In simple words: - Attribute is like a variable inside an object. - Method is like a function inside a class. Example for Player class:Attributes: - name - age - position - country - speed Methods: - run() - kick() - pass_ball() - tackle() - shoot() Example: Player object: name = "Messi" age = 36 position = "Forward" country = "Argentina" Methods: run() shoot() pass_ball()
- OOP is useful because it helps us: ✅ Organize complex code ✅ Group related data and behavior together ✅ Reuse code using inheritance ✅ Create real-world models in code ✅ Make code easier to maintain and extend Example: Instead of writing many separate functions for each player, we can create one Player class and create many player objects from it.
1.1 What is OOP?
1.2 Class and Object
1.3 Attributes and Methods
1.4 Why Use OOP?
2. 🧩 Creating Classes and Objects
- We use the
classkeyword to define a class. Class names are usually written in CamelCase. Syntax:class ClassName:# attributes and methodsExample:class Car:passHere:Car➜ class name - The
__init__method is called a constructor. It runs automatically when an object is created. We usually define attributes inside__init__. Example:class Car:def __init__(self, brand, model, color):self.brand = brandself.model = modelself.color = colorHere:brand, model, color➜ attributesself.brand, self.model, self.color➜ object attributes selfrefers to the current object. It is used to access attributes and methods inside the class. Example:self.brandmeans brand of the current object 📌selfis automatically passed when we call a method using an object.- Example:
class Car:def __init__(self, brand, model, color="blue"):self.brand = brandself.model = modelself.color = colordef display_info(self):return f"{self.brand} {self.model} in {self.color}"my_car = Car("Toyota", "Corolla", "Red")print(my_car.display_info())Output: Toyota Corolla in Red Here:Car➜ classmy_car➜ objectbrand, model, color➜ attributesdisplay_info()➜ method__init__()➜ constructor that runs automatically - We can create many objects from the same class.
Example:
class Car:def __init__(self, brand, model, color="blue"):self.brand = brandself.model = modelself.color = colordef display_info(self):return f"{self.brand} {self.model} in {self.color}"car_1 = Car("Toyota", "Corolla", "Red")car_2 = Car("Honda", "Civic")print(car_1.display_info())print(car_2.display_info())Output: Toyota Corolla in Red Honda Civic in blue 📌 Same class can create many objects with different values.
2.1 Creating a Class
2.2 __init__ Method
2.3 What is self?
2.4 Creating Object from Class
2.5 Multiple Objects
3. 🧠 Principles of OOP
- There are four main principles of OOP: 1. Inheritance 2. Polymorphism 3. Encapsulation 4. Abstraction These principles help us write organized, reusable, and maintainable code.
- Inheritance allows one class to reuse attributes and methods from another class. Example idea: Person ➜ Parent class Employee ➜ Child class Employee can reuse common details from Person, such as name, date of birth, and age.
- Polymorphism means same method name or same operator can behave differently for different objects.
Example:
A Nepali person may greet using Namaste.
An English person may greet using Hello.
Both can have the same method name:
greet()but the output can be different. 📌 In Python, polymorphism is commonly seen through method overriding and operator overloading. - Encapsulation means keeping data and methods together inside a class. It also helps control how data is accessed and modified.
Example:
A bank account should not allow direct access to balance. Instead, we use methods like:
deposit()withdraw()get_balance() - Abstraction means hiding complex internal details and showing only what is necessary.
Example:
When we drive a car, we use steering, brake, and accelerator. We do not need to understand how the engine works internally.
In Python, when we use:
"HELLO".lower()we know it converts text to lowercase. We do not need to know the internal logic of howlower()works.
3.1 Four Main Principles
3.2 Inheritance
3.3 Polymorphism
3.4 Encapsulation
3.5 Abstraction
4. 🧬 Inheritance
- Inheritance allows a new class to use attributes and methods from an existing class. The existing class is called parent class or base class. The new class is called child class or derived class. Inheritance helps us: ✅ Reuse code ✅ Avoid duplication ✅ Create relationship between classes ✅ Extend existing functionality
- Common types of inheritance: Single inheritance: A ➜ B Example: Person ➜ Employee Multilevel inheritance: A ➜ B ➜ C Example: Person ➜ Employee ➜ Manager Multiple inheritance: A + B ➜ C Example: Teacher + Researcher ➜ Professor
- Example:
class Person:def __init__(self, name, birth_year):self.name = nameself.birth_year = birth_year@propertydef age(self):return 2026 - self.birth_yeardef is_adult(self):return self.age >= 18class Employee(Person):def __init__(self, name, birth_year, employee_id, department):super().__init__(name, birth_year)self.employee_id = employee_idself.department = departmentemployee_1 = Employee("Rabindra", 1993, "E001", "IT")print(employee_1.name)print(employee_1.age)print(employee_1.employee_id)print(employee_1.is_adult())Here: Person ➜ parent class Employee ➜ child class name, birth_year, age, is_adult() ➜ inherited from Person employee_id, department ➜ defined in Employee 📌 @property allows us to use a method like an attribute. 📌 Because of @property, we can write employee_1.age instead of employee_1.age() super()is used to call the parent class method. In the example:super().__init__(name, dob)This calls the__init__method of the Person class. 📌super()helps us reuse parent class initialization code.
4.1 What is Inheritance?
4.2 Types of Inheritance
4.3 Inheritance Example
4.4 super()
5. 🔁 Polymorphism
- Polymorphism means one method name can behave differently depending on the object. Imagine different people greeting in different languages. A Nepali person says: Namaste An English person says: Hello Both are greeting, but the way of greeting is different. In OOP, this can be represented using the same method name with different behavior.
- Example:
class Nepali:def __init__(self, name):self.name = namedef greet(self):return f"Namaste, {self.name}!"class English:def __init__(self, name):self.name = namedef greet(self):return f"Hello, {self.name}!"nepali_person = Nepali("Rabindra")english_person = English("John")print(nepali_person.greet())print(english_person.greet())Output: Namaste, Rabindra! Hello, John! - Example:
people = [nepali_person, english_person]for person in people:print(person.greet())Output: Namaste, Rabindra! Hello, John! Here: Both objects havegreet()method. Python calls the correctgreet()method depending on the object. 📌 In Python, objects do not always need to come from the same parent class for polymorphism. 📌 If different objects have the same method name, Python can call that method.
5.1 What is Polymorphism?
5.2 Polymorphism Example
5.3 Polymorphism with Loop
6. 🔄 Method Overriding
- Method overriding happens when a child class defines a method with the same name as a method in the parent class. The child class method replaces the parent class method for child objects.
Example:
Animal has
speak()Dog also hasspeak()When we callspeak()on Dog object, Dog's version runs. - Example:
class Animal:def speak(self):return "Animal speaks"class Dog(Animal):def speak(self):return "Woof!"my_animal = Animal()my_dog = Dog()print(my_animal.speak())print(my_dog.speak())Output: Animal speaks Woof! Here: Dog has its ownspeak()method. So Dog overrides thespeak()method from Animal.
6.1 What is Method Overriding?
6.2 Method Overriding Example
7. ➕ Operator Overloading
- Operator overloading allows operators to behave differently for custom objects.
Example:
+adds numbers:print(10 + 20)Output: 30+concatenates strings:print("Hello" + "World")Output: HelloWorld For our own class, we can define what+should do. This is called operator overloading. - Example:
class Vector2D:def __init__(self, x, y):self.x = xself.y = ydef __add__(self, other):return Vector2D(self.x + other.x, self.y + other.y)def __repr__(self):return f"Vector2D({self.x}, {self.y})"v1 = Vector2D(1, 2)v2 = Vector2D(3, 4)v3 = v1 + v2print(v3)Output: Vector2D(4, 6) Here:v1 + v2internally calls:v1.__add__(v2)📌__add__defines how+works for Vector2D objects.
7.1 What is Operator Overloading?
7.2 Operator Overloading with __add__()
7.3 Common Operator Methods
| Operator | Internal Method |
|---|---|
| + | __add__ |
| - | __sub__ |
| * | __mul__ |
| / | __truediv__ |
| // | __floordiv__ |
| % | __mod__ |
| ** | __pow__ |
| == | __eq__ |
| != | __ne__ |
| < | __lt__ |
| > | __gt__ |
| <= | __le__ |
| >= | __ge__ |
| print() | __str__ or __repr__ |
| len() | __len__ |
8. 🔐 Encapsulation
- Encapsulation means keeping data and methods together inside a class. It also means controlling how data is accessed or changed.
Example:
A bank account has balance. We should not directly change balance from outside. Instead, we should use methods like:
deposit()withdraw()get_balance()This helps protect data from invalid changes. - In Python:
public_name: Normally accessible from outside the class._name: Treated as internal or protected by convention.__name: Triggers name mangling. 📌 Python does not have strict private variables like some other languages. 📌 Double underscore makes accidental access harder, but not impossible. - When we use double underscore, Python changes the name internally.
Example:
__balanceinside BankAccount becomes something like:_BankAccount__balanceThis is called name mangling. Because of this:account.__balancedoes not work directly. - Example:
class BankAccount:def __init__(self, owner, balance=0):self.owner = ownerself.__balance = balancedef deposit(self, amount):if amount > 0:self.__balance = self.__balance + amountelse:print("Deposit amount must be positive")def withdraw(self, amount):if 0 < amount <= self.__balance:self.__balance = self.__balance - amountelse:print("Invalid withdrawal amount")def get_balance(self):return self.__balanceaccount = BankAccount("Rabindra", 1000)account.deposit(500)account.withdraw(200)print(account.get_balance())Output: 1300 Trying direct access:print(account.__balance)Output: AttributeError: 'BankAccount' object has no attribute '__balance' 📌 We access balance usingget_balance()instead of directly accessing__balance.
8.1 What is Encapsulation?
8.2 Public, Protected, and Private Naming
8.3 Name Mangling
8.4 Encapsulation Example
9. 🎭 Abstraction
- Abstraction means hiding complex details and showing only important features. Imagine driving a car. You use: - Steering wheel - Brake - Accelerator - Gear You do not need to understand the full internal engine system to drive the car. Abstraction works in a similar way. It lets users interact with simple methods while hiding complex internal logic.
- Example:
text = "HELLO"print(text.lower())Output: hello We knowlower()converts text to lowercase. But we do not need to know howlower()works internally. This is abstraction. - In OOP, abstraction means we expose simple methods for users and hide complex internal details inside the class.
Example:
BankAccount class may provide:
deposit()withdraw()get_balance()The user only needs to call these methods. The internal balance update logic is hidden inside the class.
9.1 What is Abstraction?
9.2 Abstraction in Python
9.3 Abstraction in OOP
Practice QuestionsNot started
1. Creating Classes
Question 1 of 5
- Attributes:
brand,model,color. Default value ofcolorshould be blue. - Methods:
display_info,start_engine,stop_engine.display_infoshould return:Brand: {brand}, Model: {model}, Color: {color}start_engineshould return:Engine of {self.brand} {self.model} startedstop_engineshould return:Engine of {self.brand} {self.model} stopped - Create two objects of
Carclass:car_1(brand=Toyota, model=Corolla, color=Red) andcar_2(brand=Honda, model=Civic). - Call
display_info,start_engine, andstop_enginefor both objects and display the output.
1.1 Create a classCarwith the following details:- Attributes:
2. Inheritance
Question 2 of 5
- Create class
DeveloperinheritingEmployee. Additional attributes:github_link,is_fullstack. Method:show_profilethat returns{name} has skills: s1, s2. Git: {github_link}. - Create class
HRinheritingEmployee. Additional attributes:is_manager,onboard_rate. Method:show_profilethat returns{name} has skills: s1, s2. Onboard rate: {onboard_rate}. - 5 developers and 2 HR employees joined the company. Create objects for them with sample attributes.
- Create list
developers_listwith all developer objects. Create listhr_listwith all HR objects. - Loop through
developers_listand display developers who have both Python and Git skills.
2.1 Create a classEmployeewith attributesname,dob,salary,skill_sets, and propertyage. The age property should calculate age from dob.- Create class
3. Polymorphism and Method Overriding
Question 3 of 5
- Create class
DoginheritingAnimal. Overridespeakmethod to returnWoof! - Create class
CatinheritingAnimal. Overridespeakmethod to returnMeow! - Create objects of
Animal,Dog, andCat. - Store all objects in a list.
- Loop through the list and call
speak()for each object.
3.1 Create a classAnimalwith methodspeakthat returnsAnimal speaks.- Create class
4. Point Class and Operator Overloading
Question 4 of 5
- Define
__str__so thatprint(point)displays:P(x, y) - Overload
+and-operators. For addition,p_1 + p_2should return a new Point object with coordinates(x1 + x2, y1 + y2). For subtraction,p_1 - p_2should return a new Point object with coordinates(x1 - x2, y1 - y2). - Overload comparison operators:
<,>,<=,>=,==,!=. Comparison should be based ondist_from_origin. - Create two points:
p_1 = Point(3, 4)andp_2 = Point(1, 2). - Use
print(p_1)andprint(p_2). Expected output:P(3, 4)andP(1, 2). - Create a new point
p_3 = p_1 + p_2. Displayp_3. - Calculate distance of
p_1andp_2from origin usingdist_from_origin. - Compare
p_1andp_2using overloaded comparison operators. Example:p_1 > p_2,p_1 <= p_2
4.1 Create a classPointwith attributesx_coordinate,y_coordinate, and methoddist_from_originusing formulasqrt(x^2 + y^2).- Define
5. Encapsulation
Question 5 of 5
- Methods:
deposit,withdraw,get_balance,transfer.deposit: Add amount to balance if the amount is positive.withdraw: Subtract amount from balance if the amount is positive and less than or equal to balance.get_balance: Return current balance.transfer: Transfer amount from one account to another if the amount is valid and balance is sufficient. - Create two accounts:
account_1(owner=Rabindra) andaccount_2(owner=John). - Deposit 1000 to
account_1. - Deposit 500 to
account_2. - Withdraw 200 from
account_1. - Withdraw 100 from
account_2. - Transfer 200 from
account_1toaccount_2. - Display final balance of both accounts.
5.1 Create a classBankAccountwith attributesowner,__balance(private, default value 0).- Methods:
