Python dataclass 練習指南:欄位
dataclass 是一種簡潔表達「這個類主要裝資料」的方式。它會生成重複方法,但仍然只是普通 Python 類。理解它生成了什麼、沒有生成什麼,既能減少樣板,也能避免錯誤期待。
聲明欄位
寫帶註解的類屬性。裝飾器會用它們生成 __init__、__repr__ 和 __eq__。構造預設按位置傳參,也可以使用關鍵字參數。自動生成的 repr 在日誌和測試失敗資訊裡很有用。
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
print(Point(2, 3))以資料為中心的類
把預設值放在正確順序
帶預設值的欄位可以省略;沒有預設值的欄位仍必須提供,所以它不能跟在有預設值的欄位後面。調整欄位順序,或者給前面的欄位也加預設值。
from dataclasses import dataclass
@dataclass
class User:
name: str
active: bool = True
print(User("Ada"))
print(User("Grace", False))必填在前,可選在後
相等比較基於欄位
兩個 dataclass 實例的欄位相等時,它們就相等,即使不是同一個物件。這在測試裡很方便,但巢狀的可變欄位仍遵循自己的相等規則。不要把相等和身份混為一談。
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
print(Point(1, 2) == Point(1, 2))
print(Point(1, 2) is Point(1, 2))值相等,物件不同
用 asdict 轉換
asdict 會遞迴地把 dataclass 實例轉換成字典。列表、元組和巢狀 dataclass 也會被轉換。它適合生成類 JSON 輸出和斷言,但回傳的是副本,不是即時視圖。
from dataclasses import dataclass, asdict
@dataclass
class Item:
name: str
price: float
print(asdict(Item("tea", 3.5)))普通字典
用 frozen 表示值物件
frozen=True 禁止構造後再給屬性賦值。這讓實例更適合共用和雜湊,但不會深度凍結巢狀的可變值。它適合小型值物件,不應無差別替代所有類。
from dataclasses import dataclass
@dataclass(frozen=True)
class Item:
name: str
price: float
item = Item("tea", 3.5)
print(item.price)不可變記錄
你的練習清單
- 給每個希望自動生成的欄位加註解。
- 必填欄位放在帶預設值欄位之前。
- 記住 __eq__ 比較的是欄位值。
- 需要普通字典副本時使用 asdict。
- 小型不可變記錄可以使用 frozen=True。
常見問題
dataclass 會驗證型別嗎?
不會。註解表達意圖,但自動生成的 __init__ 不會在執行時強制檢查。
dataclass 可以有方法嗎?
可以。它仍然是普通類,可以添加方法、屬性,或在 __post_init__ 中做驗證。
asdict 是淺拷貝嗎?
它會遞迴轉換 dataclass 值,但欄位內部的可變物件仍可能共用。需要時請檢查巢狀資料。
練習 dataclasses
12 道題,覆蓋欄位、預設值、相等比較、asdict 和 frozen 實例。
繼續閱讀: