在學 Python 的 class 時,很多人都會卡在同一個問題:
❓ 為什麼有的方法要寫
self?
❓ 有的要寫cls?❓ 有的卻什麼都不用?
這不是你不會寫,而是你還沒看懂「責任層級」。
可以參考我的影片 或者接下去看文字的部分。
今天我們用一個「連鎖披薩店」的例子,一次把這三種方法講透。
一、先看完整範例(等等會一行一行拆)
class Pizza:
total_sold = 0 # 類別屬性:統計全台總銷量
def __init__(self, topping):
self.topping = topping # 實體屬性:這份披薩的配料
Pizza.total_sold += 1
# 1. 實體方法 (Instance Method)
def describe_pizza(self):
print(f"這是一份配料為 {self.topping} 的美味披薩!")
# 2. 類別方法 (Class Method)
@classmethod
def get_total_sold(cls):
print(f"📢 總部報告:全台目前已售出 {cls.total_sold} 份披薩。")
# 3. 靜態方法 (Static Method)
@staticmethod
def is_healthy(ingredient):
healthy_list = ["菠菜", "番茄", "青椒"]
return ingredient in healthy_list
二、先建立一個正確的「心智模型」
在理解語法前,請先記住這張表(非常重要)👇
方法類型在現實中像什麼關心的是誰Instance Method這一份披薩某一個物件Class Method披薩總部整個類別Static Method工具 / 計算機誰都不屬於
👉 method 的差異,不是語法,是「責任歸屬」
三、Instance Method(實體方法):處理「這一個」
程式碼
def describe_pizza(self):
print(f"這是一份配料為 {self.topping} 的美味披薩!")
為什麼一定要有 self?
因為你在問的是:
「這一份披薩是什麼?」
p1 = Pizza("起司")
p2 = Pizza("菠蘿")
p1.describe_pizza()
p2.describe_pizza()
輸出會不同,因為:
self指向的是 不同的披薩物件- 每個物件都有自己的
topping
📌 self = 物件的身份證
沒有它,Python 不知道你在跟誰說話。
四、Class Method(類別方法):處理「整體規則」
程式碼
@classmethod
def get_total_sold(cls):
print(f"📢 總部報告:全台目前已售出 {cls.total_sold} 份披薩。")
為什麼這裡用 cls,而不是 self?
因為這個問題是:
「全台一共賣了幾份披薩?」
這跟「某一份披薩」完全無關。
Pizza.get_total_sold()
你是在問 披薩這個類別本身的狀態,也就是:
total_sold = 0
📌 cls 代表的是「這個類別本身」
而不是任何一個實體。
常見錯誤(一定要知道)
❌ 這樣寫雖然能跑,但設計很怪:
def get_total_sold(self):
return Pizza.total_sold
工程師會皺眉,因為:
你明明在問「總部資料」,
為什麼要拿「某一份披薩」來問?
五、Static Method(靜態方法):純工具,不屬於任何人
程式碼
@staticmethod
def is_healthy(ingredient):
healthy_list = ["菠菜", "番茄", "青椒"]
return ingredient in healthy_list
關鍵特徵
- ❌ 不用
self - ❌ 不用
cls - ❌ 不讀任何 class / instance 資料
Pizza.is_healthy("菠菜")
那為什麼要放在 class 裡?
這是一個語意選擇:
「這個工具,跟披薩這個概念有關。」
📌 如果哪天它跟 Pizza 沒關係了,
👉 它就應該搬出去,變成普通 function。
六、三種方法的「快速判斷法」(請記這個)
當你在寫 method 時,問自己這三個問題👇
✅ 判斷流程
1️⃣ 我需不需要知道「這是誰」?
→ 要 → Instance Method (self)
2️⃣ 我是在處理「全體共用的狀態或規則」?
→ 要 → Class Method (cls)
3️⃣ 我只是提供一個小工具?
→ 是 → Static Method
七、實戰測試程式碼解析
p1 = Pizza("起司")
p2 = Pizza("菠蘿")
每建立一個 Pizza:
__init__被呼叫Pizza.total_sold += 1
p1.describe_pizza()
👉 跟「這一份披薩」有關
👉 Instance Method
Pizza.get_total_sold()
👉 跟「所有披薩」有關
👉 Class Method
Pizza.is_healthy("菠菜")
👉 不需要披薩、也不需要總部
👉 Static Method
八、為什麼這樣分,程式會「比較不亂」?
因為你在替未來的自己留下線索:
- Instance Method:
「這是某個物件的行為」 - Class Method:
「這是整個系統的規則」 - Static Method:
「這只是工具,不要亂依賴它」
📌 這就是高 cohesion(高內聚)的設計













