Bài 15: Object-Oriented Programming - OOP (Phần 2)
Mục Tiêu Bài Học
Sau khi hoàn thành bài này, bạn sẽ:
- ✅ Hiểu và implement Inheritance
- ✅ Sử dụng
super()và method overriding - ✅ Làm việc với Polymorphism
- ✅ Implement Encapsulation
- ✅ Dùng
@propertydecorator - ✅ Sử dụng Magic Methods
Inheritance (Kế Thừa)
Inheritance cho phép class kế thừa attributes và methods từ class khác.
Basic Inheritance
# Parent class (Base class / Superclass)class Animal: """Base animal class.""" def __init__(self, name, age): self.name = name self.age = age def make_sound(self): return "Some generic sound" def info(self): return f"{self.name} is {self.age} years old" # Child class (Derived class / Subclass)class Dog(Animal): """Dog inherits from Animal.""" def make_sound(self): return "Woof!" def fetch(self): return f"{self.name} is fetching the ball" class Cat(Animal): """Cat inherits from Animal.""" def make_sound(self): return "Meow!" def climb(self): return f"{self.name} is climbing a tree" # Usagedog = Dog("Buddy", 3)cat = Cat("Whiskers", 2) print(dog.info()) # Buddy is 3 years old (inherited)print(dog.make_sound()) # Woof! (overridden)print(dog.fetch()) # Buddy is fetching the ball print(cat.info()) # Whiskers is 2 years old (inherited)print(cat.make_sound()) # Meow! (overridden)print(cat.climb()) # Whiskers is climbing a tree # Check inheritanceprint(isinstance(dog, Dog)) # Trueprint(isinstance(dog, Animal)) # Trueprint(issubclass(Dog, Animal)) # True
super() Function
super() gọi methods từ parent class.
class Vehicle: """Base vehicle class.""" def __init__(self, brand, model, year): self.brand = brand self.model = model self.year = year def info(self): return f"{self.year} {self.brand} {self.model}" class Car(Vehicle): """Car class.""" def __init__(self, brand, model, year, num_doors): # Call parent __init__ super().__init__(brand, model, year) self.num_doors = num_doors def info(self): # Call parent info() and extend base_info = super().info() return f"{base_info} - {self.num_doors} doors" class ElectricCar(Car): """Electric car class.""" def __init__(self, brand, model, year, num_doors, battery_size): super().__init__(brand, model, year, num_doors) self.battery_size = battery_size def info(self): base_info = super().info() return f"{base_info} - {self.battery_size}kWh battery" # Usagecar = Car("Toyota", "Camry", 2024, 4)print(car.info()) # 2024 Toyota Camry - 4 doors ev = ElectricCar("Tesla", "Model 3", 2024, 4, 75)print(ev.info()) # 2024 Tesla Model 3 - 4 doors - 75kWh battery
Method Overriding
class Employee: """Base employee class.""" def __init__(self, name, salary): self.name = name self.salary = salary def get_bonus(self): """Calculate bonus.""" return self.salary * 0.1 class Manager(Employee): """Manager with higher bonus.""" def __init__(self, name, salary, team_size): super().__init__(name, salary) self.team_size = team_size def get_bonus(self): """Override - higher bonus.""" base_bonus = super().get_bonus() team_bonus = self.team_size * 1000 return base_bonus + team_bonus class Developer(Employee): """Developer with project bonus.""" def __init__(self, name, salary, projects_completed): super().__init__(name, salary) self.projects_completed = projects_completed def get_bonus(self): """Override - project-based bonus.""" base_bonus = super().get_bonus() project_bonus = self.projects_completed * 500 return base_bonus + project_bonus # Usageemp = Employee("Alice", 50000)mgr = Manager("Bob", 80000, 5)dev = Developer("Charlie", 70000, 10) print(f"{emp.name}: ${emp.get_bonus():.2f}") # Alice: $5000.00print(f"{mgr.name}: ${mgr.get_bonus():.2f}") # Bob: $13000.00print(f"{dev.name}: ${dev.get_bonus():.2f}") # Charlie: $12000.00
Multiple Inheritance
class Flyable: """Flying capability.""" def fly(self): return f"{self.name} is flying" class Swimmable: """Swimming capability.""" def swim(self): return f"{self.name} is swimming" class Duck(Animal, Flyable, Swimmable): """Duck can fly and swim.""" def __init__(self, name, age): super().__init__(name, age) def make_sound(self): return "Quack!" # Usageduck = Duck("Donald", 2)print(duck.info()) # Donald is 2 years oldprint(duck.make_sound()) # Quack!print(duck.fly()) # Donald is flyingprint(duck.swim()) # Donald is swimming # MRO - Method Resolution Orderprint(Duck.__mro__)# (<class 'Duck'>, <class 'Animal'>, <class 'Flyable'>, # <class 'Swimmable'>, <class 'object'>)
Polymorphism
Polymorphism cho phép objects của different classes được treat như cùng type.
Method Polymorphism
class Shape: """Base shape class.""" def area(self): raise NotImplementedError("Subclass must implement") def perimeter(self): raise NotImplementedError("Subclass must implement") class Rectangle(Shape): """Rectangle shape.""" def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height def perimeter(self): return 2 * (self.width + self.height) class Circle(Shape): """Circle shape.""" def __init__(self, radius): self.radius = radius def area(self): return 3.14159 * self.radius ** 2 def perimeter(self): return 2 * 3.14159 * self.radius class Triangle(Shape): """Triangle shape.""" def __init__(self, base, height, side1, side2, side3): self.base = base self.height = height self.side1 = side1 self.side2 = side2 self.side3 = side3 def area(self): return 0.5 * self.base * self.height def perimeter(self): return self.side1 + self.side2 + self.side3 # Polymorphism in actionshapes = [ Rectangle(5, 10), Circle(7), Triangle(6, 8, 5, 9, 10)] print("Shape Areas:")for shape in shapes: print(f"{shape.__class__.__name__}: {shape.area():.2f}") # Output:# Rectangle: 50.00# Circle: 153.94# Triangle: 24.00
Duck Typing
# "If it walks like a duck and quacks like a duck, it's a duck" class FileWriter: """Write to file.""" def write(self, data): with open('output.txt', 'a') as f: f.write(data + '\n') class ConsoleWriter: """Write to console.""" def write(self, data): print(data) class LogWriter: """Write to log.""" def write(self, data): import logging logging.info(data) def log_message(writer, message): """ Log message using any writer. Works with anything that has write() method. """ writer.write(f"[LOG] {message}") # Usage - all work the same waylog_message(FileWriter(), "File message")log_message(ConsoleWriter(), "Console message")log_message(LogWriter(), "Log message")
Encapsulation
Encapsulation ẩn internal details, expose public interface.
Private Attributes
class BankAccount: """Bank account with private balance.""" def __init__(self, owner, balance=0): self.owner = owner self.__balance = balance # Private attribute def deposit(self, amount): """Public method to deposit.""" if amount > 0: self.__balance += amount return f"Deposited ${amount}" return "Invalid amount" def withdraw(self, amount): """Public method to withdraw.""" if amount > self.__balance: return "Insufficient funds" if amount > 0: self.__balance -= amount return f"Withdrew ${amount}" return "Invalid amount" def get_balance(self): """Public method to check balance.""" return self.__balance # Usageaccount = BankAccount("Alice", 1000) # ✅ Public interfaceprint(account.deposit(500)) # Deposited $500print(account.get_balance()) # 1500 # ❌ Cannot access private attribute# print(account.__balance) # AttributeError # But can access via name mangling (not recommended!)print(account._BankAccount__balance) # 1500 (name mangling)
Protected Attributes
class Person: """Person with protected attributes.""" def __init__(self, name, age): self.name = name self._age = age # Protected (convention) def get_age(self): return self._age class Student(Person): """Student can access protected attributes.""" def __init__(self, name, age, student_id): super().__init__(name, age) self.student_id = student_id def info(self): # Can access _age from parent return f"{self.name}, {self._age} years old, ID: {self.student_id}" # Usagestudent = Student("Alice", 20, "S001")print(student.info()) # Alice, 20 years old, ID: S001print(student._age) # 20 (accessible but not recommended)
Property Decorators
@property tạo computed attributes với getter/setter.
Read-only Property
class Circle: """Circle with computed properties.""" def __init__(self, radius): self._radius = radius @property def radius(self): """Getter for radius.""" return self._radius @property def diameter(self): """Computed property.""" return self._radius * 2 @property def area(self): """Computed property.""" return 3.14159 * self._radius ** 2 @property def circumference(self): """Computed property.""" return 2 * 3.14159 * self._radius # Usagecircle = Circle(5) print(circle.radius) # 5print(circle.diameter) # 10print(circle.area) # 78.53975print(circle.circumference) # 31.4159 # Use like attributes (no parentheses!)# circle.area() ❌# circle.area ✅
Getter and Setter
class Temperature: """Temperature with validation.""" def __init__(self, celsius): self._celsius = celsius @property def celsius(self): """Get temperature in Celsius.""" return self._celsius @celsius.setter def celsius(self, value): """Set temperature in Celsius with validation.""" if value < -273.15: raise ValueError("Temperature below absolute zero!") self._celsius = value @property def fahrenheit(self): """Get temperature in Fahrenheit.""" return self._celsius * 9/5 + 32 @fahrenheit.setter def fahrenheit(self, value): """Set temperature using Fahrenheit.""" self.celsius = (value - 32) * 5/9 @property def kelvin(self): """Get temperature in Kelvin.""" return self._celsius + 273.15 # Usagetemp = Temperature(25) print(f"Celsius: {temp.celsius}") # 25print(f"Fahrenheit: {temp.fahrenheit}") # 77.0print(f"Kelvin: {temp.kelvin}") # 298.15 # Set using different unitstemp.fahrenheit = 86print(f"Celsius: {temp.celsius}") # 30.0 temp.celsius = 0print(f"Fahrenheit: {temp.fahrenheit}") # 32.0 # Validation works# temp.celsius = -300 # ValueError!
Deleter
class User: """User with deletable email.""" def __init__(self, username, email): self.username = username self._email = email @property def email(self): """Get email.""" return self._email @email.setter def email(self, value): """Set email with validation.""" if '@' not in value: raise ValueError("Invalid email") self._email = value @email.deleter def email(self): """Delete email.""" print(f"Deleting email for {self.username}") self._email = None # Usageuser = User("alice", "[email protected]") print(user.email) # [email protected]user.email = "[email protected]"print(user.email) # [email protected] del user.email # Deleting email for aliceprint(user.email) # None
Magic Methods
Magic methods (dunder methods) customize object behavior.
Comparison Methods
class Person: """Person with comparison.""" def __init__(self, name, age): self.name = name self.age = age def __eq__(self, other): """Equal to.""" return self.age == other.age def __lt__(self, other): """Less than.""" return self.age < other.age def __le__(self, other): """Less than or equal.""" return self.age <= other.age def __gt__(self, other): """Greater than.""" return self.age > other.age def __ge__(self, other): """Greater than or equal.""" return self.age >= other.age def __ne__(self, other): """Not equal.""" return self.age != other.age def __str__(self): return f"{self.name} ({self.age})" # Usageperson1 = Person("Alice", 25)person2 = Person("Bob", 30)person3 = Person("Charlie", 25) print(person1 == person3) # True (same age)print(person1 < person2) # Trueprint(person2 > person1) # True # Sortingpeople = [person2, person1, person3]people.sort() # Uses __lt__print([str(p) for p in people])# ['Alice (25)', 'Charlie (25)', 'Bob (30)']
Arithmetic Methods
class Vector: """2D Vector with arithmetic.""" def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): """Add vectors.""" return Vector(self.x + other.x, self.y + other.y) def __sub__(self, other): """Subtract vectors.""" return Vector(self.x - other.x, self.y - other.y) def __mul__(self, scalar): """Multiply by scalar.""" return Vector(self.x * scalar, self.y * scalar) def __truediv__(self, scalar): """Divide by scalar.""" return Vector(self.x / scalar, self.y / scalar) def __str__(self): return f"Vector({self.x}, {self.y})" def __repr__(self): return f"Vector({self.x}, {self.y})" # Usagev1 = Vector(2, 3)v2 = Vector(4, 5) v3 = v1 + v2print(v3) # Vector(6, 8) v4 = v2 - v1print(v4) # Vector(2, 2) v5 = v1 * 3print(v5) # Vector(6, 9) v6 = v2 / 2print(v6) # Vector(2.0, 2.5)
Container Methods
class TodoList: """Todo list with container methods.""" def __init__(self): self.tasks = [] def __len__(self): """Return number of tasks.""" return len(self.tasks) def __getitem__(self, index): """Get task by index.""" return self.tasks[index] def __setitem__(self, index, value): """Set task by index.""" self.tasks[index] = value def __delitem__(self, index): """Delete task by index.""" del self.tasks[index] def __contains__(self, item): """Check if task exists.""" return item in self.tasks def __iter__(self): """Make iterable.""" return iter(self.tasks) def add(self, task): """Add task.""" self.tasks.append(task) def __str__(self): return f"TodoList({len(self)} tasks)" # Usagetodo = TodoList()todo.add("Learn Python")todo.add("Build project")todo.add("Deploy app") print(len(todo)) # 3print(todo[0]) # Learn Pythonprint("Build project" in todo) # True # Iteratefor task in todo: print(f"- {task}") # Modifytodo[1] = "Build awesome project"del todo[2]print(len(todo)) # 2
Call Method
class Multiplier: """Callable multiplier.""" def __init__(self, factor): self.factor = factor def __call__(self, value): """Make instance callable.""" return value * self.factor # Usagedouble = Multiplier(2)triple = Multiplier(3) print(double(5)) # 10print(triple(5)) # 15 # Works like a function!numbers = [1, 2, 3, 4, 5]doubled = list(map(double, numbers))print(doubled) # [2, 4, 6, 8, 10]
Ví Dụ Thực Tế
1. E-commerce Product System
class Product: """Base product class.""" def __init__(self, name, price): self.name = name self._price = price @property def price(self): """Get price.""" return self._price @price.setter def price(self, value): """Set price with validation.""" if value < 0: raise ValueError("Price cannot be negative") self._price = value def calculate_total(self, quantity): """Calculate total price.""" return self.price * quantity def __str__(self): return f"{self.name} - ${self.price:.2f}" class PhysicalProduct(Product): """Physical product with shipping.""" def __init__(self, name, price, weight): super().__init__(name, price) self.weight = weight def calculate_shipping(self): """Calculate shipping cost.""" return self.weight * 0.5 def calculate_total(self, quantity): """Override to include shipping.""" product_total = super().calculate_total(quantity) shipping = self.calculate_shipping() return product_total + shipping class DigitalProduct(Product): """Digital product with download.""" def __init__(self, name, price, file_size): super().__init__(name, price) self.file_size = file_size def get_download_link(self): """Generate download link.""" return f"https://download.example.com/{self.name.lower().replace(' ', '-')}" class SubscriptionProduct(Product): """Subscription product.""" def __init__(self, name, monthly_price, duration_months): super().__init__(name, monthly_price) self.duration_months = duration_months def calculate_total(self, quantity=1): """Override for subscription.""" return self.price * self.duration_months # Usageproducts = [ PhysicalProduct("Laptop", 999.99, 2.5), DigitalProduct("Python Course", 49.99, 500), SubscriptionProduct("Netflix", 15.99, 12)] print("Products:")for product in products: print(f" {product}") if isinstance(product, PhysicalProduct): print(f" Shipping: ${product.calculate_shipping():.2f}") elif isinstance(product, DigitalProduct): print(f" Download: {product.get_download_link()}") elif isinstance(product, SubscriptionProduct): print(f" Duration: {product.duration_months} months") print(f" Total: ${product.calculate_total(1):.2f}")
2. Employee Management System
class Employee: """Base employee class.""" employee_count = 0 def __init__(self, name, employee_id, base_salary): self.name = name self.employee_id = employee_id self._base_salary = base_salary Employee.employee_count += 1 @property def base_salary(self): """Get base salary.""" return self._base_salary @base_salary.setter def base_salary(self, value): """Set base salary with validation.""" if value < 0: raise ValueError("Salary cannot be negative") self._base_salary = value def calculate_salary(self): """Calculate total salary.""" return self.base_salary def __str__(self): return f"{self.name} ({self.employee_id})" def __repr__(self): return f"Employee('{self.name}', '{self.employee_id}', {self.base_salary})" class FullTimeEmployee(Employee): """Full-time employee with benefits.""" def __init__(self, name, employee_id, base_salary, benefits): super().__init__(name, employee_id, base_salary) self.benefits = benefits def calculate_salary(self): """Override with benefits.""" return self.base_salary + self.benefits class PartTimeEmployee(Employee): """Part-time employee with hourly rate.""" def __init__(self, name, employee_id, hourly_rate, hours_worked): super().__init__(name, employee_id, 0) self.hourly_rate = hourly_rate self.hours_worked = hours_worked def calculate_salary(self): """Override with hours.""" return self.hourly_rate * self.hours_worked class Contractor(Employee): """Contractor with project-based pay.""" def __init__(self, name, employee_id, project_fee, projects_completed): super().__init__(name, employee_id, 0) self.project_fee = project_fee self.projects_completed = projects_completed def calculate_salary(self): """Override with project fee.""" return self.project_fee * self.projects_completed # Usageemployees = [ FullTimeEmployee("Alice", "FT001", 50000, 10000), PartTimeEmployee("Bob", "PT001", 25, 80), Contractor("Charlie", "CT001", 5000, 3)] print(f"Total Employees: {Employee.employee_count}\n")print("Payroll:")total_payroll = 0for emp in employees: salary = emp.calculate_salary() total_payroll += salary print(f" {emp}: ${salary:.2f}") print(f"\nTotal Payroll: ${total_payroll:.2f}")
3. Game Character System
class Character: """Base game character.""" def __init__(self, name, health, attack, defense): self.name = name self._health = health self.max_health = health self.attack = attack self.defense = defense @property def health(self): """Get health.""" return self._health @health.setter def health(self, value): """Set health (0 to max).""" self._health = max(0, min(value, self.max_health)) @property def is_alive(self): """Check if character is alive.""" return self._health > 0 def take_damage(self, damage): """Take damage.""" actual_damage = max(0, damage - self.defense) self.health -= actual_damage return actual_damage def heal(self, amount): """Heal character.""" old_health = self.health self.health += amount return self.health - old_health def attack_target(self, target): """Attack another character.""" damage = target.take_damage(self.attack) return damage def __str__(self): return f"{self.name} (HP: {self.health}/{self.max_health})" class Warrior(Character): """Warrior with special attack.""" def __init__(self, name): super().__init__(name, health=150, attack=20, defense=10) self.rage = 0 def take_damage(self, damage): """Override to build rage.""" actual_damage = super().take_damage(damage) self.rage += actual_damage // 5 return actual_damage def special_attack(self, target): """Powerful attack using rage.""" if self.rage >= 20: damage = target.take_damage(self.attack * 2) self.rage = 0 return damage, "CRITICAL HIT!" return 0, "Not enough rage" class Mage(Character): """Mage with mana and spells.""" def __init__(self, name): super().__init__(name, health=80, attack=30, defense=5) self.mana = 100 self.max_mana = 100 def cast_fireball(self, target): """Cast fireball spell.""" if self.mana >= 30: self.mana -= 30 damage = target.take_damage(self.attack * 1.5) return damage, "Fireball!" return 0, "Not enough mana" def regenerate_mana(self): """Regenerate mana.""" self.mana = min(self.mana + 20, self.max_mana) class Healer(Character): """Healer class.""" def __init__(self, name): super().__init__(name, health=100, attack=10, defense=8) self.mana = 100 def heal_target(self, target): """Heal another character.""" if self.mana >= 20: self.mana -= 20 amount = target.heal(40) return amount, "Healing!" return 0, "Not enough mana" # Usage - Battle simulationwarrior = Warrior("Conan")mage = Mage("Gandalf")healer = Healer("Mercy") print("=== Battle Start ===")print(warrior)print(mage)print(healer) print("\n--- Round 1 ---")damage = warrior.attack_target(mage)print(f"{warrior.name} attacks {mage.name} for {damage} damage")print(mage) damage, msg = mage.cast_fireball(warrior)print(f"{mage.name} casts fireball on {warrior.name} for {damage} damage - {msg}")print(warrior) amount, msg = healer.heal_target(mage)print(f"{healer.name} heals {mage.name} for {amount} HP - {msg}")print(mage) print("\n--- Round 2 ---")damage, msg = warrior.special_attack(mage)print(f"{warrior.name} special attack on {mage.name} for {damage} damage - {msg}")print(mage)
4. File System Abstraction
from abc import ABC, abstractmethodfrom datetime import datetime class FileSystemItem(ABC): """Abstract base class for file system items.""" def __init__(self, name): self.name = name self.created_at = datetime.now() @abstractmethod def get_size(self): """Get size in bytes.""" pass @abstractmethod def display(self, indent=0): """Display item.""" pass def __str__(self): return self.name class File(FileSystemItem): """File class.""" def __init__(self, name, content=""): super().__init__(name) self._content = content @property def content(self): """Get file content.""" return self._content @content.setter def content(self, value): """Set file content.""" self._content = value def get_size(self): """Return content size.""" return len(self._content) def display(self, indent=0): """Display file.""" print(" " * indent + f"📄 {self.name} ({self.get_size()} bytes)") class Directory(FileSystemItem): """Directory class.""" def __init__(self, name): super().__init__(name) self.children = [] def add(self, item): """Add file or directory.""" self.children.append(item) def remove(self, item_name): """Remove file or directory.""" self.children = [c for c in self.children if c.name != item_name] def get_size(self): """Total size of all children.""" return sum(child.get_size() for child in self.children) def display(self, indent=0): """Display directory tree.""" print(" " * indent + f"📁 {self.name}/") for child in self.children: child.display(indent + 1) def __len__(self): """Number of items.""" return len(self.children) def __getitem__(self, index): """Get child by index.""" return self.children[index] # Usageroot = Directory("root") # Create structuredocs = Directory("documents")docs.add(File("resume.txt", "My resume content..."))docs.add(File("cover_letter.txt", "Dear hiring manager...")) images = Directory("images")images.add(File("photo1.jpg", "binary data" * 1000))images.add(File("photo2.jpg", "binary data" * 1500)) root.add(docs)root.add(images)root.add(File("readme.txt", "This is readme")) # Displayroot.display() print(f"\nTotal size: {root.get_size()} bytes")print(f"Items in images: {len(images)}")
5. Custom Collection with Magic Methods
class Playlist: """Music playlist with magic methods.""" def __init__(self, name): self.name = name self.songs = [] def add(self, song): """Add song.""" self.songs.append(song) def __len__(self): """Number of songs.""" return len(self.songs) def __getitem__(self, index): """Get song by index.""" return self.songs[index] def __setitem__(self, index, song): """Set song by index.""" self.songs[index] = song def __contains__(self, song): """Check if song in playlist.""" return song in self.songs def __iter__(self): """Make iterable.""" return iter(self.songs) def __add__(self, other): """Merge playlists.""" new_playlist = Playlist(f"{self.name} + {other.name}") new_playlist.songs = self.songs + other.songs return new_playlist def __str__(self): return f"Playlist: {self.name} ({len(self)} songs)" def __repr__(self): return f"Playlist('{self.name}', {len(self)} songs)" class Song: """Song class.""" def __init__(self, title, artist, duration): self.title = title self.artist = artist self.duration = duration # seconds def __str__(self): mins = self.duration // 60 secs = self.duration % 60 return f"{self.title} - {self.artist} ({mins}:{secs:02d})" def __eq__(self, other): """Songs equal if same title and artist.""" return self.title == other.title and self.artist == other.artist # Usageplaylist1 = Playlist("Rock Classics")playlist1.add(Song("Bohemian Rhapsody", "Queen", 354))playlist1.add(Song("Stairway to Heaven", "Led Zeppelin", 482))playlist1.add(Song("Hotel California", "Eagles", 391)) playlist2 = Playlist("Pop Hits")playlist2.add(Song("Shape of You", "Ed Sheeran", 234))playlist2.add(Song("Blinding Lights", "The Weeknd", 200)) print(playlist1)print(playlist2) # Container methodsprint(f"\nSongs in {playlist1.name}: {len(playlist1)}")print(f"First song: {playlist1[0]}") # Check membershipsong = Song("Hotel California", "Eagles", 391)print(f"\n'{song.title}' in playlist: {song in playlist1}") # Iterateprint(f"\n{playlist1.name} tracklist:")for i, song in enumerate(playlist1, 1): print(f"{i}. {song}") # Merge playlistsmixed = playlist1 + playlist2print(f"\n{mixed}")print(f"Total songs: {len(mixed)}")
Best Practices
# 1. Use ABC for abstract base classesfrom abc import ABC, abstractmethod class Animal(ABC): @abstractmethod def make_sound(self): pass # 2. Call super().__init__() in child classesclass Dog(Animal): def __init__(self, name): super().__init__() self.name = name # 3. Use @property for computed attributesclass Circle: @property def area(self): return 3.14159 * self.radius ** 2 # 4. Implement __str__ and __repr__class Person: def __str__(self): return f"{self.name}" def __repr__(self): return f"Person('{self.name}', {self.age})" # 5. Use composition over inheritance when appropriateclass Car: def __init__(self): self.engine = Engine() # Composition self.wheels = [Wheel() for _ in range(4)]
Bài Tập Thực Hành
Bài 1: Shape Hierarchy
Tạo hierarchy: Shape → Rectangle, Circle, Triangle
- Implement
area()vàperimeter() - Add
__str__và comparison methods - Create list of shapes và sort by area
Bài 2: Account System
Tạo BankAccount và subclasses: SavingsAccount, CheckingAccount
- Different interest rates
- Transaction limits
- Property decorators cho balance
- Magic methods để compare accounts
Bài 3: Game Inventory
Tạo Item base class và subclasses: Weapon, Armor, Potion
Inventoryclass với magic methods__len__,__getitem__,__contains__- Add/remove items
- Calculate total value
Bài 4: Social Media
Tạo Post base class và: TextPost, ImagePost, VideoPost
Userclass với posts- Like/comment functionality
__add__để merge user feeds- Property cho engagement rate
Bài 5: Task Management
Tạo Task base class và: TodoTask, RecurringTask, ProjectTask
TaskManagervới filtering- Priority comparison
- Status properties
- Iterator pattern
Tóm Tắt
✅ Inheritance: Class kế thừa từ parent class
✅ super(): Gọi methods từ parent class
✅ Polymorphism: Same interface, different implementations
✅ Encapsulation: Private (__attr) và protected (_attr)
✅ @property: Getter/setter cho attributes
✅ Magic Methods: Customize object behavior
__str__,__repr__: String representation__eq__,__lt__: Comparisons__add__,__mul__: Arithmetic__len__,__getitem__: Container behavior
Kết Thúc Module Python Cơ Bản
🎉 Chúc mừng! Bạn đã hoàn thành Module Python Cơ Bản với 15 bài học:
- Giới thiệu Python
- Variables & Data Types
- Operators
- Strings
- Lists
- Tuples
- Dictionaries
- Sets
- Control Flow
- Loops
- Functions
- Modules & Packages
- File I/O
- Error Handling
- Object-Oriented Programming
Bài Tiếp Theo
Bài 16: - Python Basics - Practices & Projects 🚀
Remember:
- Inheritance = Code reusability
- Polymorphism = Flexibility
- Encapsulation = Data protection
- Properties = Controlled access
- Magic methods = Python magic! ✨