Dataclass trong Python: viết class gọn và rõ ràng hơn

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____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.

Lên đầu trang