專項練習 · 9 分鐘閱讀

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)

不可變記錄

你的練習清單

常見問題

dataclass 會驗證型別嗎?

不會。註解表達意圖,但自動生成的 __init__ 不會在執行時強制檢查。

dataclass 可以有方法嗎?

可以。它仍然是普通類,可以添加方法、屬性,或在 __post_init__ 中做驗證。

asdict 是淺拷貝嗎?

它會遞迴轉換 dataclass 值,但欄位內部的可變物件仍可能共用。需要時請檢查巢狀資料。

練習 dataclasses

12 道題,覆蓋欄位、預設值、相等比較、asdict 和 frozen 實例。

打開練習

繼續閱讀: