Viết một class chỉ để chứa dữ liệu thường tốn rất nhiều dòng lặp lại. Từ Python 3.7, dataclass sinh sẵn những phần đó cho bạn.
Trước và sau
# Cách truyền thống
class SanPham:
def __init__(self, ten, gia, so_luong):
self.ten = ten
self.gia = gia
self.so_luong = so_luong
def __repr__(self):
return f"SanPham({self.ten!r}, {self.gia}, {self.so_luong})"
# Với dataclass
from dataclasses import dataclass
@dataclass
class SanPham:
ten: str
gia: float
so_luong: int = 0
Bản dataclass tự có __init__, __repr__ và __eq__.
sp = SanPham("Bàn phím", 450000, 3)
print(sp) # SanPham(ten='Bàn phím', gia=450000, so_luong=3)
print(sp == SanPham("Bàn phím", 450000, 3)) # True
Giá trị mặc định là list hoặc dict
from dataclasses import dataclass, field
@dataclass
class DonHang:
ma: str
mat_hang: list = field(default_factory=list) # KHÔNG viết = []
Đây là lỗi kinh điển: dùng = [] làm mặc định khiến mọi đối tượng chia sẻ chung một list. default_factory tạo list mới cho từng đối tượng.
Bất biến với frozen
@dataclass(frozen=True)
class ToaDo:
x: float
y: float
diem = ToaDo(1.0, 2.0)
# diem.x = 5 -> FrozenInstanceError
Đối tượng frozen có thể dùng làm key của dict hoặc phần tử của set.
Thêm phương thức và tiện ích
from dataclasses import asdict
@dataclass
class SanPham:
ten: str
gia: float
so_luong: int = 0
def thanh_tien(self) -> float:
return self.gia * self.so_luong
print(asdict(SanPham("Chuột", 200000, 2))) # đổi sang dict, tiện xuất JSON
Khi cần kiểm tra kiểu dữ liệu chặt chẽ lúc chạy, hãy cân nhắc Pydantic. Còn để gom dữ liệu gọn gàng trong nội bộ chương trình, dataclass là lựa chọn nhẹ và đủ dùng.
