Back to blog

Python Giai Đoạn 2: OOP & Tính Năng Nâng Cao

pythonoopprogrammingadvancedtype-hints
Python Giai Đoạn 2: OOP & Tính Năng Nâng Cao

Python Giai Đoạn 2: OOP & Tính Năng Nâng Cao

Chào mừng bạn đến với Giai Đoạn 2 của Lộ Trình Học Python! Trong giai đoạn này, bạn sẽ thành thạo lập trình hướng đối tượng (OOP) và các tính năng nâng cao đặc trưng của Python giúp bạn viết code sạch, dễ bảo trì và chuyên nghiệp.

Những Gì Bạn Sẽ Học

✅ Classes và objects trong Python
✅ Kế thừa và ghi đè phương thức
✅ Property decorators và phương thức đặc biệt
✅ Dataclasses (Python 3.10+)
✅ List/dict/set comprehensions
✅ Generator expressions
✅ Decorators cơ bản
✅ Context managers
✅ Type hints nền tảng

Điều Kiện Tiên Quyết

Trước khi bắt đầu giai đoạn này, bạn nên thành thạo:

  • Cú pháp Python và các kiểu dữ liệu cơ bản (Giai Đoạn 1)
  • Functions và control flow
  • Lists, dictionaries, và cấu trúc dữ liệu cơ bản
  • File I/O và xử lý ngoại lệ

1. Classes và Objects

Classes là bản thiết kế để tạo objects. Chúng đóng gói dữ liệu (thuộc tính) và hành vi (phương thức) lại với nhau.

Cú Pháp Class Cơ Bản

class User:
    """Đại diện cho người dùng trong hệ thống."""
 
    def __init__(self, username: str, email: str) -> None:
        """Khởi tạo người dùng mới."""
        self.username = username
        self.email = email
        self.is_active = True  # Giá trị mặc định
 
    def deactivate(self) -> None:
        """Vô hiệu hóa tài khoản người dùng."""
        self.is_active = False
 
    def __str__(self) -> str:
        """Biểu diễn chuỗi cho người dùng."""
        status = "active" if self.is_active else "inactive"
        return f"User({self.username}, {status})"
 
# Tạo instances
user1 = User("alice", "[email protected]")
user2 = User("bob", "[email protected]")
 
print(user1)  # User(alice, active)
user1.deactivate()
print(user1)  # User(alice, inactive)

Phương Thức Đặc Biệt (Magic Methods)

Python cung cấp các phương thức đặc biệt cho phép bạn tùy chỉnh hành vi của object:

class BankAccount:
    """Đại diện cho tài khoản ngân hàng."""
 
    def __init__(self, account_number: str, balance: float = 0.0) -> None:
        self.account_number = account_number
        self.balance = balance
 
    def __str__(self) -> str:
        """Biểu diễn chuỗi thân thiện với người dùng."""
        return f"Account {self.account_number}: ${self.balance:.2f}"
 
    def __repr__(self) -> str:
        """Biểu diễn cho developer (dùng cho debug)."""
        return f"BankAccount('{self.account_number}', {self.balance})"
 
    def __eq__(self, other: object) -> bool:
        """Kiểm tra bằng nhau dựa trên số tài khoản."""
        if not isinstance(other, BankAccount):
            return NotImplemented
        return self.account_number == other.account_number
 
    def __add__(self, amount: float) -> "BankAccount":
        """Cho phép thêm tiền bằng toán tử +."""
        self.balance += amount
        return self
 
# Sử dụng
account = BankAccount("12345", 1000.0)
print(str(account))   # Account 12345: $1000.00
print(repr(account))  # BankAccount('12345', 1000.0)
 
account + 500  # Thêm tiền bằng +
print(account)  # Account 12345: $1500.00

Các phương thức đặc biệt phổ biến:

  • __init__: Constructor
  • __str__: Chuỗi thân thiện (dùng bởi print())
  • __repr__: Biểu diễn cho developer (dùng trong REPL)
  • __eq__, __lt__, __gt__: Toán tử so sánh
  • __len__: Độ dài (cho len())
  • __getitem__, __setitem__: Truy cập chỉ mục

2. Kế Thừa và Đa Hình

Kế thừa cho phép các class kế thừa thuộc tính và phương thức từ class cha.

Kế Thừa Cơ Bản

from typing import Optional
 
class Animal:
    """Class cơ sở cho tất cả động vật."""
 
    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age
 
    def speak(self) -> str:
        """Phát ra âm thanh (sẽ được ghi đè)."""
        raise NotImplementedError("Subclasses phải implement speak()")
 
    def info(self) -> str:
        """Lấy thông tin động vật."""
        return f"{self.name} {self.age} tuổi"
 
class Dog(Animal):
    """Chó là một loại động vật."""
 
    def __init__(self, name: str, age: int, breed: str) -> None:
        super().__init__(name, age)  # Gọi constructor cha
        self.breed = breed
 
    def speak(self) -> str:
        """Chó sủa."""
        return "Gâu gâu!"
 
    def fetch(self, item: str) -> str:
        """Hành vi đặc trưng của chó."""
        return f"{self.name} nhặt {item}"
 
class Cat(Animal):
    """Mèo là một loại động vật."""
 
    def __init__(self, name: str, age: int, indoor: bool = True) -> None:
        super().__init__(name, age)
        self.indoor = indoor
 
    def speak(self) -> str:
        """Mèo kêu."""
        return "Meo meo!"
 
# Đa hình: các kiểu khác nhau, giao diện giống nhau
animals: list[Animal] = [
    Dog("Buddy", 5, "Golden Retriever"),
    Cat("Whiskers", 3),
    Dog("Max", 2, "Beagle"),
]
 
for animal in animals:
    print(f"{animal.name} kêu: {animal.speak()}")
# Buddy kêu: Gâu gâu!
# Whiskers kêu: Meo meo!
# Max kêu: Gâu gâu!

Đa Kế Thừa và Method Resolution Order (MRO)

class Flyable:
    """Mixin cho khả năng bay."""
 
    def fly(self) -> str:
        return "Tôi có thể bay!"
 
class Swimmable:
    """Mixin cho khả năng bơi."""
 
    def swim(self) -> str:
        return "Tôi có thể bơi!"
 
class Duck(Animal, Flyable, Swimmable):
    """Vịt có thể bay và bơi."""
 
    def speak(self) -> str:
        return "Quạc quạc!"
 
duck = Duck("Donald", 2)
print(duck.speak())  # Quạc quạc!
print(duck.fly())    # Tôi có thể bay!
print(duck.swim())   # Tôi có thể bơi!
 
# Kiểm tra Method Resolution Order
print(Duck.__mro__)
# (<class 'Duck'>, <class 'Animal'>, <class 'Flyable'>,
#  <class 'Swimmable'>, <class 'object'>)

3. Properties và Descriptors

Properties cung cấp cách tùy chỉnh truy cập thuộc tính trong khi duy trì giao diện sạch.

Sử Dụng @property Decorator

class Temperature:
    """Nhiệt độ với Celsius và Fahrenheit."""
 
    def __init__(self, celsius: float) -> None:
        self._celsius = celsius  # Thuộc tính private
 
    @property
    def celsius(self) -> float:
        """Lấy nhiệt độ theo Celsius."""
        return self._celsius
 
    @celsius.setter
    def celsius(self, value: float) -> None:
        """Đặt nhiệt độ Celsius với validation."""
        if value < -273.15:
            raise ValueError("Nhiệt độ dưới độ không tuyệt đối!")
        self._celsius = value
 
    @property
    def fahrenheit(self) -> float:
        """Lấy nhiệt độ theo Fahrenheit (property tính toán)."""
        return self._celsius * 9/5 + 32
 
    @fahrenheit.setter
    def fahrenheit(self, value: float) -> None:
        """Đặt nhiệt độ bằng Fahrenheit."""
        self.celsius = (value - 32) * 5/9  # Dùng celsius setter
 
# Sử dụng
temp = Temperature(25)
print(f"{temp.celsius}°C = {temp.fahrenheit}°F")  # 25.0°C = 77.0°F
 
temp.celsius = 30
print(f"{temp.celsius}°C = {temp.fahrenheit}°F")  # 30.0°C = 86.0°F
 
temp.fahrenheit = 32
print(f"{temp.celsius}°C")  # 0.0°C

Class Methods và Static Methods

from datetime import datetime
 
class Person:
    """Người với năm sinh."""
 
    population = 0  # Biến class
 
    def __init__(self, name: str, birth_year: int) -> None:
        self.name = name
        self.birth_year = birth_year
        Person.population += 1
 
    def get_age(self) -> int:
        """Instance method: cần self."""
        return datetime.now().year - self.birth_year
 
    @classmethod
    def from_birth_date(cls, name: str, birth_date: str) -> "Person":
        """Class method: constructor thay thế."""
        year = int(birth_date.split("-")[0])
        return cls(name, year)
 
    @staticmethod
    def is_adult(age: int) -> bool:
        """Static method: không cần class hay instance."""
        return age >= 18
 
# Sử dụng
person1 = Person("Alice", 1990)
person2 = Person.from_birth_date("Bob", "1985-05-15")  # Class method
 
print(person1.get_age())  # ví dụ, 36
print(Person.is_adult(person1.get_age()))  # True
print(f"Dân số: {Person.population}")  # 2

4. Dataclasses (Python 3.10+)

Dataclasses tự động tạo các phương thức đặc biệt cho classes lưu trữ dữ liệu.

Dataclass Cơ Bản

from dataclasses import dataclass, field
from typing import Optional
 
@dataclass
class Product:
    """Sản phẩm trong hệ thống kho."""
    name: str
    price: float
    quantity: int = 0
    category: Optional[str] = None
 
    def total_value(self) -> float:
        """Tính tổng giá trị kho."""
        return self.price * self.quantity
 
# Tự động có __init__, __repr__, __eq__
product = Product("Laptop", 999.99, 10, "Electronics")
print(product)
# Product(name='Laptop', price=999.99, quantity=10, category='Electronics')
 
print(product.total_value())  # 9999.90

Tính Năng Dataclass Nâng Cao

from dataclasses import dataclass, field
from datetime import datetime
 
@dataclass(frozen=True)  # Dataclass bất biến
class Point:
    """Điểm 2D bất biến."""
    x: float
    y: float
 
    def distance_from_origin(self) -> float:
        return (self.x**2 + self.y**2) ** 0.5
 
@dataclass
class Order:
    """Đơn hàng với trường được tạo tự động."""
    customer_id: str
    items: list[Product] = field(default_factory=list)  # Default có thể thay đổi
    order_date: datetime = field(default_factory=datetime.now)
    order_id: str = field(init=False)  # Được tạo, không có trong __init__
 
    def __post_init__(self) -> None:
        """Được gọi sau __init__ để đặt trường được tạo."""
        self.order_id = f"ORD-{self.customer_id}-{self.order_date.timestamp()}"
 
    def add_item(self, product: Product) -> None:
        self.items.append(product)
 
    def total_cost(self) -> float:
        return sum(p.price * p.quantity for p in self.items)
 
# Sử dụng
order = Order("CUST123")
order.add_item(Product("Mouse", 29.99, 2))
order.add_item(Product("Keyboard", 79.99, 1))
print(order.order_id)  # ORD-CUST123-1737897600.0
print(f"Tổng: ${order.total_cost():.2f}")  # Tổng: $139.97

5. Comprehensions

Comprehensions cung cấp cách ngắn gọn để tạo lists, dictionaries, và sets.

List Comprehensions

# Cú pháp cơ bản: [biểu_thức for phần_tử in iterable if điều_kiện]
 
# Không dùng comprehension
squares = []
for x in range(10):
    squares.append(x**2)
 
# Dùng comprehension (sạch hơn)
squares = [x**2 for x in range(10)]
print(squares)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
 
# Với lọc
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares)  # [0, 4, 16, 36, 64]
 
# Vòng lặp lồng nhau
pairs = [(x, y) for x in range(3) for y in range(3) if x != y]
print(pairs)  # [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
 
# Biến đổi chuỗi
names = ["alice", "bob", "charlie"]
capitalized = [name.title() for name in names]
print(capitalized)  # ['Alice', 'Bob', 'Charlie']

Dictionary Comprehensions

# Cú pháp cơ bản: {key_expr: value_expr for item in iterable}
 
# Tạo mapping từ số sang bình phương
squares_dict = {x: x**2 for x in range(6)}
print(squares_dict)  # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
 
# Đổi keys và values
original = {"a": 1, "b": 2, "c": 3}
swapped = {v: k for k, v in original.items()}
print(swapped)  # {1: 'a', 2: 'b', 3: 'c'}
 
# Lọc dictionary
scores = {"Alice": 85, "Bob": 92, "Charlie": 78, "David": 95}
high_scorers = {name: score for name, score in scores.items() if score >= 90}
print(high_scorers)  # {'Bob': 92, 'David': 95}

Set Comprehensions

# Cú pháp cơ bản: {biểu_thức for phần_tử in iterable}
 
# Độ dài từ duy nhất
text = "the quick brown fox jumps over the lazy dog"
word_lengths = {len(word) for word in text.split()}
print(word_lengths)  # {3, 4, 5}
 
# Loại bỏ trùng lặp với biến đổi
numbers = [1, -2, 3, -4, 5, -1, 2]
absolute_values = {abs(n) for n in numbers}
print(absolute_values)  # {1, 2, 3, 4, 5}

Generator Expressions

Generator expressions giống list comprehensions nhưng tạo iterators (lazy evaluation).

# Cú pháp: (biểu_thức for phần_tử in iterable)
# Dùng dấu ngoặc đơn thay vì ngoặc vuông
 
# List comprehension: tạo list đầy đủ trong bộ nhớ
squares_list = [x**2 for x in range(1000000)]  # Dùng ~4MB bộ nhớ
 
# Generator expression: lazy evaluation
squares_gen = (x**2 for x in range(1000000))  # Dùng ~80 bytes
 
# Lặp một lần
for sq in squares_gen:
    if sq > 100:
        print(sq)
        break  # 121
 
# Hữu ích cho datasets lớn
def read_large_file(file_path: str):
    """Generator để đọc file từng dòng."""
    with open(file_path) as f:
        # Xử lý dòng lazily mà không load toàn bộ file
        return (line.strip().upper() for line in f if line.strip())
 
# Dùng trong tham số hàm
total = sum(x**2 for x in range(100))  # Không cần ngoặc thêm
print(total)  # 328350

6. Decorators Cơ Bản

Decorators là hàm thay đổi hành vi của hàm hoặc class khác.

Function Decorators

from functools import wraps
from time import time, sleep
from typing import Callable, Any
 
def timer(func: Callable) -> Callable:
    """Decorator để đo thời gian thực thi hàm."""
    @wraps(func)  # Bảo toàn metadata của hàm gốc
    def wrapper(*args: Any, **kwargs: Any) -> Any:
        start = time()
        result = func(*args, **kwargs)
        end = time()
        print(f"{func.__name__} mất {end - start:.4f}s")
        return result
    return wrapper
 
@timer
def slow_function() -> None:
    """Một hàm chậm."""
    sleep(1)
    print("Xong!")
 
slow_function()
# Xong!
# slow_function mất 1.0012s

Decorators Với Tham Số

from typing import Callable, Any
 
def repeat(times: int) -> Callable:
    """Decorator lặp lại thực thi hàm."""
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> Any:
            for _ in range(times):
                result = func(*args, **kwargs)
            return result  # Trả về kết quả cuối
        return wrapper
    return decorator
 
@repeat(times=3)
def greet(name: str) -> str:
    message = f"Xin chào, {name}!"
    print(message)
    return message
 
greet("Alice")
# Xin chào, Alice!
# Xin chào, Alice!
# Xin chào, Alice!

Built-in Decorators

class Circle:
    """Hình tròn với tính toán diện tích cached."""
 
    def __init__(self, radius: float) -> None:
        self._radius = radius
 
    @property
    def radius(self) -> float:
        return self._radius
 
    @radius.setter
    def radius(self, value: float) -> None:
        if value < 0:
            raise ValueError("Bán kính không thể âm")
        self._radius = value
 
    @staticmethod
    def from_diameter(diameter: float) -> "Circle":
        """Tạo hình tròn từ đường kính."""
        return Circle(diameter / 2)
 
    @classmethod
    def unit_circle(cls) -> "Circle":
        """Tạo hình tròn đơn vị."""
        return cls(1.0)
 
circle = Circle.unit_circle()
print(circle.radius)  # 1.0

Để tìm hiểu toàn diện về decorators, xem Python Decorators Chuyên Sâu.


7. Context Managers

Context managers xử lý quản lý tài nguyên (setup/teardown) tự động bằng câu lệnh with.

Sử Dụng Built-in Context Managers

# Xử lý file (tự động đóng)
with open("data.txt", "w") as f:
    f.write("Xin chào!")
# File tự động đóng ở đây
 
# Nhiều context managers
with open("input.txt") as infile, open("output.txt", "w") as outfile:
    data = infile.read()
    outfile.write(data.upper())

Tạo Custom Context Managers

from typing import Optional
 
class DatabaseConnection:
    """Kết nối database với cleanup tự động."""
 
    def __init__(self, host: str, port: int) -> None:
        self.host = host
        self.port = port
        self.connection: Optional[str] = None
 
    def __enter__(self) -> "DatabaseConnection":
        """Setup: được gọi khi vào block 'with'."""
        print(f"Đang kết nối tới {self.host}:{self.port}...")
        self.connection = f"Connection to {self.host}"
        return self
 
    def __exit__(self, exc_type, exc_val, exc_tb) -> bool:
        """Cleanup: được gọi khi thoát block 'with'."""
        print(f"Đang đóng kết nối tới {self.host}...")
        self.connection = None
        # Trả về False để lan truyền exceptions, True để ngăn chặn
        return False
 
    def query(self, sql: str) -> str:
        """Thực thi query."""
        if not self.connection:
            raise RuntimeError("Không có kết nối active")
        return f"Kết quả của: {sql}"
 
# Sử dụng
with DatabaseConnection("localhost", 5432) as db:
    result = db.query("SELECT * FROM users")
    print(result)
# Kết nối tự động đóng sau block
# Đang kết nối tới localhost:5432...
# Kết quả của: SELECT * FROM users
# Đang đóng kết nối tới localhost...

Context Manager Dùng contextlib

from contextlib import contextmanager
from typing import Iterator
 
@contextmanager
def temporary_setting(config: dict, key: str, value: Any) -> Iterator[None]:
    """Tạm thời thay đổi giá trị config."""
    old_value = config.get(key)
    config[key] = value
    try:
        yield  # Code trong block 'with' chạy ở đây
    finally:
        # Khôi phục giá trị gốc
        if old_value is None:
            config.pop(key, None)
        else:
            config[key] = old_value
 
# Sử dụng
config = {"debug": False, "timeout": 30}
print(config)  # {'debug': False, 'timeout': 30}
 
with temporary_setting(config, "debug", True):
    print(config)  # {'debug': True, 'timeout': 30}
 
print(config)  # {'debug': False, 'timeout': 30} - đã khôi phục

8. Type Hints Nền Tảng

Type hints cải thiện khả năng đọc code và cho phép kiểm tra kiểu tĩnh với các công cụ như mypy.

Type Hints Cơ Bản

from typing import List, Dict, Set, Tuple, Optional, Union
 
# Chú thích hàm
def greet(name: str, age: int) -> str:
    """Chào một người."""
    return f"Xin chào {name}, bạn {age} tuổi"
 
# Chú thích biến
username: str = "alice"
user_id: int = 12345
is_active: bool = True
 
# Collections (kiểu cũ - Python 3.9+)
from typing import List, Dict
names: List[str] = ["Alice", "Bob", "Charlie"]
scores: Dict[str, int] = {"Alice": 95, "Bob": 87}
 
# Kiểu hiện đại (Python 3.10+)
names: list[str] = ["Alice", "Bob", "Charlie"]
scores: dict[str, int] = {"Alice": 95, "Bob": 87}
coordinates: tuple[float, float] = (10.5, 20.3)

Optional và Union Types

from typing import Optional, Union
 
# Optional[X] là viết tắt cho Union[X, None]
def find_user(user_id: int) -> Optional[str]:
    """Tìm user theo ID, trả về None nếu không tìm thấy."""
    users = {1: "Alice", 2: "Bob"}
    return users.get(user_id)  # Trả về str hoặc None
 
# Union cho nhiều kiểu có thể
def process_id(user_id: Union[int, str]) -> str:
    """Xử lý user ID là int hoặc string."""
    return str(user_id)
 
# Python 3.10+ dùng | thay cho Union
def process_id_modern(user_id: int | str) -> str:
    """Cú pháp union hiện đại."""
    return str(user_id)

Type Hints Cho Classes

from typing import ClassVar
from dataclasses import dataclass
 
@dataclass
class Employee:
    """Nhân viên với type hints."""
    name: str
    employee_id: int
    salary: float
    department: Optional[str] = None
 
    # Class variable (chia sẻ giữa instances)
    company_name: ClassVar[str] = "TechCorp"
 
    def give_raise(self, amount: float) -> None:
        """Tăng lương."""
        self.salary += amount
 
    def get_info(self) -> dict[str, str | int | float]:
        """Trả về thông tin nhân viên dạng dict."""
        return {
            "name": self.name,
            "id": self.employee_id,
            "salary": self.salary,
        }

Type Aliases

from typing import TypeAlias
 
# Tạo type aliases cho kiểu phức tạp
UserId: TypeAlias = int
Username: TypeAlias = str
UserData: TypeAlias = dict[str, Union[str, int, bool]]
 
def create_user(user_id: UserId, username: Username) -> UserData:
    """Tạo dữ liệu user."""
    return {
        "id": user_id,
        "username": username,
        "active": True,
    }

Để tìm hiểu toàn diện về type hints, xem Type Hints & Typing Chuyên Sâu.


9. Ví Dụ Thực Tế: Xây Dựng Task Manager

Hãy kết hợp mọi thứ chúng ta đã học vào một ví dụ thực tế:

from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional, ClassVar
from enum import Enum
 
class Priority(Enum):
    """Mức độ ưu tiên task."""
    LOW = 1
    MEDIUM = 2
    HIGH = 3
    URGENT = 4
 
class Status(Enum):
    """Trạng thái task."""
    TODO = "todo"
    IN_PROGRESS = "in_progress"
    DONE = "done"
 
@dataclass
class Task:
    """Đại diện cho task trong task manager."""
    title: str
    description: str = ""
    priority: Priority = Priority.MEDIUM
    status: Status = Status.TODO
    created_at: datetime = field(default_factory=datetime.now)
    completed_at: Optional[datetime] = None
 
    task_count: ClassVar[int] = 0
 
    def __post_init__(self) -> None:
        Task.task_count += 1
 
    def complete(self) -> None:
        """Đánh dấu task hoàn thành."""
        self.status = Status.DONE
        self.completed_at = datetime.now()
 
    @property
    def is_overdue(self) -> bool:
        """Kiểm tra task quá hạn (>7 ngày và chưa xong)."""
        if self.status == Status.DONE:
            return False
        age = (datetime.now() - self.created_at).days
        return age > 7
 
    def __str__(self) -> str:
        status_icon = "✅" if self.status == Status.DONE else "⏳"
        return f"{status_icon} [{self.priority.name}] {self.title}"
 
class TaskManager:
    """Quản lý tập hợp các tasks."""
 
    def __init__(self) -> None:
        self.tasks: list[Task] = []
 
    def add_task(self, task: Task) -> None:
        """Thêm task vào manager."""
        self.tasks.append(task)
 
    def get_tasks_by_status(self, status: Status) -> list[Task]:
        """Lấy tất cả tasks với trạng thái cụ thể."""
        return [task for task in self.tasks if task.status == status]
 
    def get_high_priority_tasks(self) -> list[Task]:
        """Lấy tasks ưu tiên cao và khẩn cấp."""
        return [
            task for task in self.tasks
            if task.priority in (Priority.HIGH, Priority.URGENT)
            and task.status != Status.DONE
        ]
 
    @property
    def completion_rate(self) -> float:
        """Tính tỷ lệ hoàn thành theo phần trăm."""
        if not self.tasks:
            return 0.0
        completed = len([t for t in self.tasks if t.status == Status.DONE])
        return (completed / len(self.tasks)) * 100
 
    def __len__(self) -> int:
        """Trả về số lượng tasks."""
        return len(self.tasks)
 
    def __str__(self) -> str:
        return f"TaskManager({len(self.tasks)} tasks, {self.completion_rate:.1f}% hoàn thành)"
 
# Sử dụng
manager = TaskManager()
 
# Thêm tasks
manager.add_task(Task(
    "Implement user authentication",
    "Thêm chức năng login/logout",
    Priority.HIGH
))
 
manager.add_task(Task(
    "Viết tài liệu",
    "Tài liệu hóa API endpoints",
    Priority.MEDIUM
))
 
manager.add_task(Task(
    "Sửa bug nghiêm trọng",
    "Sửa lỗi xử lý thanh toán",
    Priority.URGENT
))
 
# Đánh dấu task đầu tiên hoàn thành
manager.tasks[0].complete()
 
# Lấy tasks ưu tiên cao
urgent_tasks = manager.get_high_priority_tasks()
for task in urgent_tasks:
    print(task)
# ⏳ [URGENT] Sửa bug nghiêm trọng
 
print(manager)  # TaskManager(3 tasks, 33.3% hoàn thành)
print(f"Tổng tasks đã tạo: {Task.task_count}")  # 3

10. Best Practices

✅ Dùng dataclasses cho lưu trữ dữ liệu: Giảm boilerplate code
✅ Ưu tiên composition hơn inheritance: Quan hệ "has-a" thường rõ ràng hơn "is-a"
✅ Dùng type hints: Cải thiện khả năng đọc code và bắt bugs sớm
✅ Giữ comprehensions dễ đọc: Nếu phức tạp, dùng loop thay vì
✅ Dùng properties cho thuộc tính tính toán: Duy trì giao diện sạch
✅ Tuân theo quy ước đặt tên: _private, __name_mangled, public
✅ Dùng context managers cho tài nguyên: Đảm bảo cleanup đúng cách
✅ Viết docstrings: Tài liệu hóa classes và phương thức public


11. Lỗi Thường Gặp

❌ Tham số mặc định có thể thay đổi: Dùng field(default_factory=list) trong dataclasses
❌ Quên self: Tham số đầu tiên của instance methods phải là self
❌ Lạm dụng inheritance: Phân cấp kế thừa sâu khó bảo trì
❌ Comprehensions phức tạp: Chia thành nhiều dòng hoặc dùng loops cho rõ ràng
❌ Không dùng @wraps: Luôn dùng functools.wraps trong decorators
❌ Sửa đổi lists trong khi lặp: Tạo bản sao trước hoặc dùng list comprehension

# ❌ TỆ: Tham số mặc định có thể thay đổi
def add_item(item: str, items: list = []) -> list:
    items.append(item)
    return items
 
# ✅ TỐT: Dùng None và tạo list mới
def add_item(item: str, items: Optional[list] = None) -> list:
    if items is None:
        items = []
    items.append(item)
    return items
 
# ❌ TỆ: Sửa đổi list trong khi lặp
numbers = [1, 2, 3, 4, 5]
for num in numbers:
    if num % 2 == 0:
        numbers.remove(num)  # Bỏ qua phần tử!
 
# ✅ TỐT: Dùng list comprehension
numbers = [1, 2, 3, 4, 5]
numbers = [num for num in numbers if num % 2 != 0]

Tóm Tắt và Điểm Chính

Trong giai đoạn này, bạn đã học:

✅ Classes và OOP: Tạo code có thể tái sử dụng, có tổ chức với classes và kế thừa
✅ Phương thức đặc biệt: Tùy chỉnh hành vi object với magic methods
✅ Properties: Kiểm soát truy cập thuộc tính với @property decorator
✅ Dataclasses: Đơn giản hóa classes lưu trữ dữ liệu với phương thức tự động
✅ Comprehensions: Viết biến đổi ngắn gọn, dễ đọc cho lists, dicts, và sets
✅ Generators: Xử lý datasets lớn hiệu quả với lazy evaluation
✅ Decorators: Sửa đổi hành vi hàm một cách sạch và có thể tái sử dụng
✅ Context managers: Quản lý tài nguyên an toàn với câu lệnh with
✅ Type hints: Cải thiện chất lượng code với static typing

Bài Tập Thực Hành

  1. Xây Dựng Hệ Thống Thư Viện: Tạo classes cho Book, Member, và Library với chức năng mượn/trả
  2. Implement Decorator: Viết decorator @cache memoizes kết quả hàm
  3. Pipeline Xử Lý Dữ Liệu: Dùng comprehensions và generators để xử lý dataset lớn hiệu quả

Bước Tiếp Theo

Tiếp tục với Giai Đoạn 3: Thư Viện Chuẩn & Công Cụ để học về thư viện chuẩn mạnh mẽ của Python và các công cụ phát triển chuyên nghiệp.

Trước đó: Giai Đoạn 1: Nền Tảng Python

Các Bài Chuyên Sâu Liên Quan:


Thuộc chuỗi bài Lộ Trình Học Python

📬 Đăng ký nhận bản tin

Nhận những bài viết mới nhất qua email mỗi tuần. Không spam, hủy đăng ký bất cứ lúc nào.

Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất cứ lúc nào.

💬 Comments

Đăng nhập để bình luận

Chúng tôi sẽ không đăng bất cứ điều gì mà không có sự cho phép của bạn.