第 15 課 · 入門 · 19 分鐘

Python 類與物件

把資料和操作資料的函式組合成一個可復用的小物件。

類定義__init__ 與 self方法與實例

每張訂單都帶著飲料、杯型和價格,三個函式把它們分開傳來傳去。類可以讓一個物件把它們裝在一起。這個物件應該能為自己做什麼?

類(class)是建立物件的藍圖。物件用屬性儲存資料,用方法提供行為。先從訂單這樣的小記錄開始,一次只加一個方法。 你還會區分類屬性與實例屬性、在 __init__ 中守住不變數,並寫出有用的 __repr__。

定義類

class 關鍵字建立藍圖。建立新物件時會執行 __init__。self 指向目前這個物件,屬性通過 self.name 賦值。

class Order:
    def __init__(self, drink, price):
        self.drink = drink
        self.price = price

order = Order("latte", 4.5)
print(order.drink)
print(order.price)

一個小類

添加方法

方法就是定義在類裡的函式,第一個參數是 self。它可以讀取物件屬性並回傳結果;呼叫時不需要手動傳入 self。

class Order:
    def __init__(self, drink, price, quantity=1):
        self.drink = drink
        self.price = price
        self.quantity = quantity

    def total(self):
        return self.price * self.quantity

print(Order("latte", 4.5, 2).total())

帶預設值的方法

建立獨立物件

每個實例都有自己的屬性值。走訪物件列表,通常比維護幾個平行列表更清楚。逐個列印欄位,檢查每個物件儲存了什麼。

class Order:
    def __init__(self, drink, price):
        self.drink = drink
        self.price = price

orders = [Order("latte", 4.5), Order("tea", 3.0)]
for order in orders:
    print(order.drink, order.price)

物件列表

類屬性是所有實例共用的

在類體裡賦值的屬性屬於類,不屬於某個物件。可變的類屬性會被所有實例共用。每個物件自己的預設值要放進 __init__;只有確實該共用的值才留在類上。

class Order:
    tags = []

    def __init__(self, drink):
        self.drink = drink

first = Order("latte")
second = Order("tea")
first.tags.append("gift")
print(second.tags)
print(first.tags is second.tags)

所有訂單共用同一個列表

物件建立時就驗證不變數

物件不應該以非法狀態存在。在 __init__ 裡檢查價格和數量,帶著壞值拋出 ValueError。呼叫方只需處理一個清楚的失敗,而不是過很久才發現總價是負數。

class Order:
    def __init__(self, drink, price):
        if price < 0:
            raise ValueError(f"negative price: {price}")
        self.drink = drink
        self.price = price

for price in [4.5, -1]:
    try:
        order = Order("latte", price)
        print(order.drink, order.price)
    except ValueError as error:
        print(type(error).__name__, error)

在物件存在之前拒絕壞值

__repr__ 應該幫助偵錯

沒有 __str__ 時,print(order) 會退回到 __repr__。好的 __repr__ 顯示類名和能識別物件的欄位。它面向開發者,所以要明確,不要寫成一句營銷文案。

class Order:
    def __init__(self, drink, price, quantity=1):
        self.drink = drink
        self.price = price
        self.quantity = quantity

    def __repr__(self):
        return f"Order(drink={self.drink!r}, price={self.price}, quantity={self.quantity})"

print(Order("latte", 4.5, 2))

顯示類名和識別欄位

本課要點

  • 類定義物件的形狀。
  • __init__ 初始化新實例。
  • self 指向目前實例。
  • 方法可以讀取屬性並回傳計算結果。
  • 可變預設值放進 __init__;類屬性由所有實例共用。

常見錯誤

  • 定義方法時忘記寫 self。
  • 只定義了類,卻從未呼叫它建立物件。
  • 不小心讓多個實例共用同一個可變屬性。
  • 把類級別的列表當成每個物件自己的標籤列表。
輪到你

建立帶 drink 和 price 的 Order 類,再為兩個訂單列印格式化總價。

動手試試

改改變數、先預測輸出,再執行程式碼。第一次點擊「執行程式碼」時會下載 Python 執行時,可能需要幾秒鐘。

瀏覽器內 Python本機執行 · 無需帳號
首次執行會從 CDN 下載 Pyodide。修改後點擊「執行程式碼」。

練習本課

12 道題,作答後立即看到解釋。

查看 12 道題答案開始練習
← 排序與 key模組與匯入 →