Object-Oriented Programming (OOP)
# Object-Oriented Programming (OOP)
Welcome to Chapter 18! OOP is one of the most important programming paradigms. It lets you model real-world entities as objects with properties and behaviors.
---
1. Learning Objectives
- Understand OOP concepts (classes, objects, encapsulation).
- Create classes with constructors and methods.
- Use instance and class variables.
- Implement special/magic methods.
- Build a bank account system.
---
2. Classes and Objects
```python id="py18ex1" class Dog: # Class variable (shared by all instances) species = "Canis familiaris" # Constructor (initializer) def init_(self, name, breed, age): # Instance variables (unique to each object) self.name = name self.breed = breed self.age = age # Instance method def bark(self): return f"{self.name} says Woof! 🐕" def info(self): return f"{self.name} ({self.breed}), {self.age} years old"
# Creating objects (instances) dog1 = Dog("Buddy", "Labrador", 3) dog2 = Dog("Luna", "German Shepherd", 5)
print(dog1.bark()) # Buddy says Woof! 🐕 print(dog2.info()) # Luna (German Shepherd), 5 years old print(Dog.species) # Canis familiaris
Class vs Object: ┌──────────────────┐ │ Class: Dog │ ← Blueprint │ - name │ │ - breed │ │ - bark() │ └──────┬───────────┘ │ Creates ┌───┴───┐ ▼ ▼ ┌──────┐ ┌──────┐ │dog1 │ │dog2 │ ← Instances │Buddy │ │Luna │ └──────┘ └──────┘
python id="py18ex2" class Student: def init_(self, name, grade): self.name = name # self.name = instance variable self.grade = grade def promote(self): self.grade += 1 # Modify instance variable print(f"{self.name} promoted to grade {self.grade}!")
s = Student("Alice", 10) s.promote() # Alice promoted to grade 11!
python id="py18ex3" class Employee: # Class variable company = "TechCorp" employeecount = 0 def _init(self, name, salary): self.name = name # Instance variable self.salary = salary # Instance variable Employee.employeecount += 1
e1 = Employee("Alice", 80000) e2 = Employee("Bob", 75000)
print(Employee.company) # TechCorp print(Employee.employee_count) # 2 print(e1.name) # Alice
python id="py18ex4" class MyClass: count = 0 def init(self, value): self.value = value MyClass.count += 1 # Instance method — accesses instance data def show(self): return f"Value: {self.value}" # Class method — accesses class data @classmethod def getcount(cls): return f"Total instances: {cls.count}" # Static method — no access to instance or class @staticmethod def validate(value): return isinstance(value, (int, float))
obj1 = MyClass(10) obj2 = MyClass(20)
print(obj1.show()) # Value: 10 print(MyClass.get_count()) # Total instances: 2 print(MyClass.validate(42)) # True
python id="py18ex5" class Vector: def init(self, x, y): self.x = x self.y = y def str(self): return f"Vector({self.x}, {self.y})" def repr(self): return f"Vector(x={self.x}, y={self.y})" def add(self, other): return Vector(self.x + other.x, self.y + other.y) def len(self): return int((self.x2 + self.y2)**0.5) def eq_(self, other): return self.x == other.x and self.y == other.y
v1 = Vector(3, 4) v2 = Vector(1, 2)
print(v1) # Vector(3, 4) print(v1 + v2) # Vector(4, 6) print(len(v1)) # 5 print(v1 == v2) # False
python id="py18ex6" class Temperature: def init(self, celsius): self.celsius = celsius @property def celsius(self): return self.celsius @celsius.setter def celsius(self, value): if value < -273.15: raise ValueError("Below absolute zero!") self.celsius = value @property def fahrenheit(self): return (self._celsius * 9/5) + 32
temp = Temperature(100) print(temp.celsius) # 100 print(temp.fahrenheit) # 212.0 temp.celsius = 0 print(temp.fahrenheit) # 32.0
python id="py18project" class BankAccount: bankname = "PyBank" def _init(self, owner, balance=0): self.owner = owner self.balance = balance self.transactions = [] @property def balance(self): return self.balance def deposit(self, amount): if amount <= 0: raise ValueError("Deposit must be positive!") self.balance += amount self.transactions.append(f"+${amount:.2f}") print(f" ✅ Deposited ${amount:.2f}") def withdraw(self, amount): if amount <= 0: raise ValueError("Withdrawal must be positive!") if amount > self.balance: print(f" ❌ Insufficient funds!") return self.balance -= amount self.transactions.append(f"-${amount:.2f}") print(f" ✅ Withdrew ${amount:.2f}") def statement(self): print(f"\n {'='*35}") print(f" {self.bankname} - Account Statement") print(f" {'='*35}") print(f" Owner: {self.owner}") print(f" Balance: ${self.balance:.2f}") print(f" Transactions: {len(self.transactions)}") for t in self.transactions[-5:]: print(f" {t}") print(f" {'='*35}") def str(self): return f"BankAccount({self.owner}, ${self.balance:.2f})"
# Demo
account = BankAccount("Alice", 1000)
account.deposit(500)
account.withdraw(200)
account.withdraw(100)
account.statement()
``
---
9. MCQs with Answers
Q1: _init is:
A) Destructor B) Constructor C) Iterator D) Generator
Answer: B
Q2: self refers to:
A) The class B) Current instance C) Parent class D) Module
Answer: B
Q3: Class variables are shared by: A) One instance B) All instances C) No instances D) Only methods Answer: B
Q4: @classmethod receives:
A) self B) cls C) Nothing D) Both
Answer: B
Q5: @staticmethod receives:
A) self B) cls C) Nothing special D) Both
Answer: C
Q6: str is called by:
A) repr() B) print() C) len() D) init()
Answer: B
Q7: @property creates:
A) Class variable B) Getter method C) Static method D) Private variable
Answer: B
Q8: variable convention means:
A) Public B) Private (by convention) C) Protected D) Constant
Answer: B
Q9: Dunder methods start and end with: A) B) C) # D) @ Answer: B — Double underscores.
Q10: Can a class have multiple constructors?
A) Yes, directly B) No, use @classmethod alternatives C) Only in Python 2 D) Only with metaclasses
Answer: B — Python uses @classmethod for alternative constructors.
---
10. Interview Questions
-
1.
What is self
?Reference to the current instance, passed automatically as the first argument to instance methods.
- 2. Class variable vs instance variable? Class variables are shared across all instances; instance variables are unique to each object.
-
3.
What are magic/dunder methods? Special methods with double underscores that Python calls implicitly (e.g., init
,str,add).
- 4. What is the @property decorator? Creates getter/setter methods that look like attributes, enabling validation and computed properties.
-
5.
Can you have multiple init methods? No. Use @classmethod
for alternative constructors.
---
11. Summary
- Classes are blueprints; objects are instances.
-
init
initializes objects;selfrefers to the current instance.
- Class variables are shared; instance variables are unique.
- @classmethod, @staticmethod, and @property provide different method types.
-
Magic methods (str
,add_`, etc.) customize object behavior.
---
12. Next Chapter Recommendation
In Chapter 19: Inheritance and Polymorphism, you'll learn to build class hierarchies and reuse code! 🚀