Lập trình hướng đối tượng (OOP) giúp tổ chức chương trình lớn thành các “vật” có dữ liệu và hành vi. Bài này dạy định nghĩa lớp, thuộc tính, phương thức, property và phương thức đặc biệt.
Bạn sẽ học được
- Định nghĩa lớp với __init__ và phương thức
- Phân biệt thuộc tính đối tượng và thuộc tính lớp
- Dùng @property, @classmethod, @staticmethod
- Viết __str__, __repr__, __eq__
Thuật ngữ cần biết
- Lớp (class)
- Bản thiết kế mô tả dữ liệu và hành vi.
- Đối tượng (instance)
- Một thực thể cụ thể tạo từ lớp.
- self
- Tham chiếu tới chính đối tượng đang xét.
- Dunder method
- Phương thức đặc biệt dạng __ten__.
Khái niệm và lý thuyết
Lớp gom thuộc tính (dữ liệu) và phương thức (hành vi) lại một chỗ. Mỗi đối tượng có bản dữ liệu riêng nhưng dùng chung phương thức. Bốn nguyên lý: đóng gói, kế thừa, đa hình, trừu tượng.
Python không có private thật; quy ước tên bắt đầu bằng _ là “nội bộ, đừng dùng từ ngoài”. @property cho phép kiểm tra dữ liệu khi gán mà vẫn dùng cú pháp truy cập thuộc tính bình thường.
Lớp đầu tiên
class SinhVien:
truong = "Đại học Tây Bắc" # thuộc tính lớp, dùng chung
def __init__(self, ma: str, ho_ten: str):
self.ma = ma # thuộc tính đối tượng
self.ho_ten = ho_ten
self._diem: list[float] = []
def them_diem(self, d: float) -> None:
if not 0 <= d <= 10:
raise ValueError("Điểm phải từ 0 đến 10")
self._diem.append(d)
@property
def diem_tb(self) -> float:
return sum(self._diem) / len(self._diem) if self._diem else 0.0
def __str__(self):
return f"{self.ma} - {self.ho_ten} ({self.diem_tb:.2f})"
sv = SinhVien("SV01", "Lò Văn An")
sv.them_diem(8); sv.them_diem(9)
print(sv) # SV01 - Lò Văn An (8.50)Property có setter, classmethod, staticmethod
class NhietDo:
def __init__(self, c: float):
self.c = c # đi qua setter
@property
def c(self): return self._c
@c.setter
def c(self, gia_tri):
if gia_tri < -273.15: raise ValueError("Dưới độ không tuyệt đối")
self._c = gia_tri
@property
def f(self): return self._c * 9 / 5 + 32
@classmethod
def tu_f(cls, f): return cls((f - 32) * 5 / 9) # constructor thay thế
@staticmethod
def hop_le(x): return x >= -273.15Phương thức đặc biệt
| Phương thức | Được gọi khi |
|---|---|
| __str__ | print(obj), str(obj) |
| __repr__ | Hiển thị trong console, gỡ lỗi |
| __eq__, __lt__ | So sánh ==, < |
| __len__ | len(obj) |
| __add__ | obj1 + obj2 |
class PhanSo:
def __init__(self, tu, mau): self.tu, self.mau = tu, mau
def __add__(self, o): return PhanSo(self.tu * o.mau + o.tu * self.mau, self.mau * o.mau)
def __repr__(self): return f"{self.tu}/{self.mau}"
print(PhanSo(1, 2) + PhanSo(1, 3)) # 5/6Mẹo hay
Đặt tên lớp theo CamelCase (SinhVien), tên hàm/biến theo snake_case (them_diem) theo chuẩn PEP 8.
Lưu ý
Quên tham số self ở phương thức gây lỗi “takes 0 positional arguments but 1 was given”.
Thực hành
- Viết lớp
TaiKhoancó nạp, rút (không cho âm), lịch sử giao dịch. - Viết lớp
HinhChuNhatcó property dien_tich, chu_vi và __eq__. - Thêm classmethod
tu_chuoi("SV01;Lò Văn An")cho SinhVien. - Viết lớp
Vector2Dhỗ trợ +, -, * số và abs().
Tóm tắt bài học
- Lớp = thuộc tính + phương thức; self là đối tượng hiện tại.
- @property kiểm soát truy cập dữ liệu.
- classmethod tạo constructor thay thế; staticmethod là hàm tiện ích.
- Dunder method giúp đối tượng dùng như kiểu có sẵn.