Dataclasses
ปัญหา boilerplate
หัวข้อที่มีชื่อว่า “ปัญหา boilerplate”Class ที่เก็บข้อมูลมักต้องการ __init__, __repr__ และ __eq__ — ทั้งหมดเขียนด้วยมือด้วย logic เหมือนกัน: copy constructor arguments ลงใน self.attr, format attributes เป็น string, เปรียบเทียบ attribute ทีละตัว
@dataclass สร้างทั้งหมดนี้จาก type annotations ระดับ class
from dataclasses import dataclass
@dataclassclass Point: x: float y: floatPython สร้าง:
__init__(self, x: float, y: float)ที่กำหนดself.xและself.y__repr__ที่ return"Point(x=1.0, y=2.0)"__eq__ที่เปรียบเทียบทุก field
Default values
หัวข้อที่มีชื่อว่า “Default values”Scalar defaults ทำงานเหมือน keyword arguments:
@dataclassclass Config: host: str = "localhost" port: int = 8080 debug: bool = Falsefield() สำหรับ mutable defaults
หัวข้อที่มีชื่อว่า “field() สำหรับ mutable defaults”ไม่สามารถใช้ mutable object (list, dict) เป็น default โดยตรง — Python จะใช้ instance เดียวร่วมกันระหว่าง object ทั้งหมด
ใช้ field(default_factory=...) แทน:
from dataclasses import dataclass, field
@dataclassclass Inventory: name: str tags: list = field(default_factory=list) quantity: int = 0field ยังรับ:
| Parameter | ผล |
|---|---|
default_factory | เรียกโดยไม่มี argument เพื่อสร้าง default ของแต่ละ instance |
repr=False | ยกเว้น field จาก __repr__ |
compare=False | ยกเว้น field จาก __eq__ และ __lt__ |
init=False | ยกเว้นจาก __init__; กำหนดด้วยตนเองใน __post_init__ |
frozen=True — immutable records
หัวข้อที่มีชื่อว่า “frozen=True — immutable records”frozen=True ทำให้ dataclass ไม่สามารถแก้ไขได้: สร้าง __setattr__ และ __delattr__ ที่ raise FrozenInstanceError และยังสร้าง __hash__ ทำให้ใช้ frozen instances เป็น dict keys หรือใน sets ได้
@dataclass(frozen=True)class Color: red: int green: int blue: intเพิ่ม custom methods
หัวข้อที่มีชื่อว่า “เพิ่ม custom methods”Dataclass ยังคงเป็น class ปกติ — เพิ่ม method ใดก็ได้ตามต้องการ:
@dataclassclass Point: x: float y: float
def distance_from_origin(self) -> float: return (self.x ** 2 + self.y ** 2) ** 0.5Demo รันได้จริง
หัวข้อที่มีชื่อว่า “Demo รันได้จริง”from dataclasses import dataclass, field
@dataclassclass Point: x: float y: float
def distance_from_origin(self) -> float: return (self.x ** 2 + self.y ** 2) ** 0.5
@dataclassclass Inventory: name: str tags: list = field(default_factory=list) quantity: int = 0
def add_tag(self, tag: str) -> None: self.tags.append(tag)
@dataclass(frozen=True)class Color: red: int green: int blue: int
p = Point(3.0, 4.0)print(p)print(p.distance_from_origin())
item = Inventory("Widget")item.add_tag("sale")item.add_tag("clearance")print(item)
red = Color(255, 0, 0)print(red)print(red == Color(255, 0, 0))Loading Python runtime (first run only)…