昨天我們用函式做了一個簡單的 ATM 模擬器:
雖然有點像真的 ATM,但其實隱藏了一些小危機喔:
如果有 10 個人要用 ATM,每個人都有不同的名字和不同的餘額,
我們就要寫一大堆變數來存放這些人。
每次操作時,還要記得傳「餘額」進去函式裡,容易搞混。
這時候,就要用到
物件導向程式設計(Object-Oriented Programming,簡稱 OOP)。
我們先用生活中的例子來解釋:
想像「房子的設計圖」 → 這就是 類別(Class)。
它定義了一個房子長什麼樣子,有幾個房間,幾扇窗戶。
用設計圖蓋出來的「真正的房子」 → 這就是 物件(Object)。
每一棟房子雖然長得差不多,但都有自己的顏色、大小、住的人。
我們把上面說的概念切換到程式世界:
這樣說可能還是會有點抽象,那我們來實際看個例子吧!
我們來設計一個帳戶的藍圖,取名叫 Account
。
class Account:
# 建構子(初始化帳戶)
def __init__(self, name, balance):
self.name = name # 帳戶擁有者
self.balance = balance # 餘額
# 查詢餘額
def check_balance(self):
print(f"{self.name} 的餘額是:{self.balance} 元")
# 存錢
def deposit(self, amount):
self.balance += amount
print(f"{self.name} 存了 {amount} 元,現在餘額是:{self.balance} 元")
# 領錢
def withdraw(self, amount):
if amount <= self.balance:
self.balance -= amount
print(f"{self.name} 領了 {amount} 元,現在餘額是:{self.balance} 元")
else:
print("餘額不足!")
哇哇哇,是不是有看到熟悉的def(函式)!
這邊我來用比較白話一點的方式講解~
class Account:
→ 建立一個類別,名字叫 Account
。
__init__
→ 這是一個「建構子」,每次我們要建立帳戶時,這個函式會自動執行。
self.name
:代表帳戶的「名字」。
self.balance
:代表帳戶的「餘額」。
self
→ 意思是「這個物件自己」。
如果有 100 個帳戶,每個帳戶都有自己的 name
和 balance
,self
幫你區分誰是誰。
deposit
和 withdraw
→ 就是帳戶能做的動作,我們把它叫做 方法(method)。
範例:
# 建立兩個帳戶
acc1 = Account("小明", 1000) # 小明的帳戶,起始金額 1000
acc2 = Account("小華", 500) # 小華的帳戶,起始金額 500
# 查詢餘額
acc1.check_balance() # 小明查詢餘額
acc2.check_balance() # 小華查詢餘額
# 存錢
acc1.deposit(300) # 小明存 300 元
# 領錢
acc2.withdraw(600) # 小華領 600 元
輸出:
很酷吧?現在每個帳戶都「自己記得」自己的餘額,程式變得清楚很多!
第一次接觸物件導向的讀者們可能會覺得有一點點抽象,
沒關係!我們來一步步分解我們剛剛的程式碼!
基礎先打好,明天接觸更進階的才會更順利~
__init__
?先看一段程式碼:
class Account:
def __init__(self, name, balance):
self.name = name
self.balance = balance
這邊有個關鍵字:__init__
(兩邊各有兩個底線)。
__init__
就會自動跑一次,幫我們把物件的資料準備好。舉例來說:
acc1 = Account("小明", 1000)
這行的意思是:
acc1
。__init__
,把 "小明"
塞進 self.name
,把 1000
塞進 self.balance
。acc1
就會帶著「小明」和「1000 元」誕生。你可以把 __init__
想成「帳戶開戶表單」,填進去的資料就是每個帳戶的獨特資訊。
self
又是什麼?self
是一個「自我指標」。self
代表「小明的帳戶」。self
代表「小華的帳戶」。self.name = name
self.balance = balance
意思就是:
「把傳進來的名字和金額,分別存到這個帳戶物件的 name 和 balance裡。」
.
)當我們建立好帳戶物件後,就可以用「點」.
來呼叫方法。
(會不會太白話哈哈)
acc1 = Account("小明", 1000)
acc1.check_balance()
acc1.deposit(500)
這裡的acc1代表「小明的帳戶」,所以acc1代表「小明的帳戶」,
所以acc1.check_balance()的意思是:
「讓小明這個帳戶,執行check_balance這個動作。」
如果是小華:
acc2 = Account("小華", 500)
acc2.withdraw(200)
就是「小華這個帳戶,執行 withdraw
這個動作」。
小明和小華雖然用同一個類別 Account
建立,
但各自的餘額是分開的,互不影響。
接下來我會介紹一下我當初在學物件導向這邊,
常常混淆的地方:
self
必須寫,但不用傳很多人以為呼叫方法時要自己傳 self
,例如:
acc1.deposit(self, 500) # ❌ 錯誤!
其實不用這樣寫!因為Python 會自動把物件自己傳進 self
。
正確的寫法:
acc1.deposit(500)
__init__
名字一定要打對有些人會不小心少打底線,變成 init
,結果 Python 根本不會自動執行。
要記住:前後各兩條底線 → __init__
。
acc1 = Account("小明", 1000)
acc2 = Account("小華", 500)
acc1.deposit(200)
print(acc2.balance) # 還是 500,不會被改到
很多新手會誤以為「存錢」會影響到所有帳戶,這是不對的。
每個物件都是獨立的!(這也是物件導向的優點!)
模擬線上購物,每個商品都是「物件」,購物車可以顯示總金額。
完成這題練習題可以讓讀者更了解:
1.如何用 class 定義物件(商品、購物車)
2.物件之間如何互動(購物車裝商品)
3.init、self 的用途
4.如何用方法(method)設計功能,如加入商品、計算總價
那話不多說!我們一起來看看吧!!
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
class Cart:
def __init__(self):
self.items = []
def add_item(self, product):
self.items.append(product)
print(f"加入 {product.name} (${product.price}) 到購物車")
def total(self):
total_price = sum(item.price for item in self.items)
print(f"購物車總金額:${total_price}")
# 建立商品
apple = Product("蘋果", 30)
book = Product("書", 120)
milk = Product("牛奶",80)
banana = Product("香蕉",40)
# 建立購物車
cart = Cart()
cart.add_item(apple)
cart.add_item(book)
cart.add_item(banana)
cart.total()
輸出:
這邊來程式說明一下~
首先,第一部分:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
說明:Product 是商品類別,每個商品都有「名稱」與「價格」兩個屬性。
創建物件時會自動呼叫 init 來初始化。
第二部分:
class Cart:
def __init__(self):
self.items = [] # 用 list 儲存購物車裡的所有商品
def add_item(self, product):
self.items.append(product)
print(f"加入 {product.name} (${product.price}) 到購物車")
def total(self):
total_price = sum(item.price for item in self.items)
print(f"購物車總金額:${total_price}")
說明:
Cart 是購物車類別,包含:
self.items:用來存放所有商品的清單
add_item():加入商品的方法
total():計算並印出購物車總金額
這題跟上面那題又有一點點不太一樣喔~
這題我們要來讓使用者自己輸入!!
這題的學習目標是:
1.如何建立一個可互動的系統(使用 while True 與 input)
2.如何用物件儲存資料(學生資訊)
3.物件方法應用:顯示與更新資料
一起來看看吧~(下方一樣會附上程式說明)
class Student:
def __init__(self, name, grade, school):
self.name = name
self.grade = grade
self.school = school
def show_info(self):
print(f"姓名:{self.name}, 年級:{self.grade}, 學校:{self.school}")
def update_info(self, grade=None, school=None):
if grade:
self.grade = grade
if school:
self.school = school
print(f"✅ {self.name} 的資料已更新!")
# 學生資料清單
students = []
while True:
print("\n--- 補習班學生資料系統 ---")
print("1. 新增學生")
print("2. 查看所有學生")
print("3. 查詢特定學生")
print("4. 修改學生資料")
print("5. 離開系統")
choice = input("請選擇功能:")
if choice == "1":
name = input("輸入學生姓名:")
grade = input("輸入學生年級:")
school = input("輸入學生學校:")
s = Student(name, grade, school)
students.append(s)
print(f"✅ 已新增學生 {name}")
elif choice == "2":
if not students:
print("目前沒有學生資料。")
else:
print("📋 學生清單:")
for s in students:
s.show_info()
elif choice == "3":
target = input("輸入要查詢的學生姓名:")
found = False
for s in students:
if s.name == target:
s.show_info()
found = True
break
if not found:
print("❌ 查無此學生。")
elif choice == "4":
target = input("輸入要修改的學生姓名:")
found = False
for s in students:
if s.name == target:
new_grade = input("輸入新年級(可留空):")
new_school = input("輸入新學校(可留空):")
s.update_info(grade=new_grade if new_grade else None,
school=new_school if new_school else None)
found = True
break
if not found:
print("❌ 查無此學生。")
elif choice == "5":
print("📚 系統結束,再見!")
break
else:
print("❌ 無效選項,請重新輸入。")
輸出:
我們先來看第一段:
class Student:
def __init__(self, name, grade, school):
self.name = name
self.grade = grade
self.school = school
說明:Student 類別代表一位學生,包含姓名、年級、學校三個屬性。
第二段:
def show_info(self):
print(f"姓名:{self.name}, 年級:{self.grade}, 學校:{self.school}")
def update_info(self, grade=None, school=None):
if grade:
self.grade = grade
if school:
self.school = school
print(f"✅ {self.name} 的資料已更新!")
說明:show_info() 用來顯示學生資料,update_info() 則用來修改年級或學校。
第三段:(主程式part)
students = [] # 儲存所有學生物件
while True:
print("\n--- 補習班學生資料系統 ---")
print("1. 新增學生")
print("2. 查看所有學生")
print("3. 查詢特定學生")
print("4. 修改學生資料")
print("5. 離開系統")
choice = input("請選擇功能:")
說明:是不是看到了熟悉的while loop!
這段主要建立了一個主選單,讓使用者可以輸入選項操作系統,不同選項會對應不同功能。
第四段:(功能解釋)
1.新增學生(自行輸入資料)
name = input("輸入學生姓名:")
grade = input("輸入學生年級:")
school = input("輸入學生學校:")
s = Student(name, grade, school)
students.append(s)
print(f"✅ 已新增學生 {name}")
2.查看所有學生
列出所有 Student 物件,並呼叫 show_info()。
3.查詢特定學生
根據名字搜尋,若找到就顯示資料。
4.修改學生資料
輸入要修改的學生姓名,再更新年級或學校(可留空)。
5.離開系統
結束 while True 迴圈,跳出系統。
有沒有覺得觀念更清楚了呢?那我們今天的內容也告一段落了~
今天我們把「類別」這個看似抽象的東西,
轉換成了生活化的例子:帳戶、購物車、補習班學生系統。
學到的重點是:
__init__
就像是「初始化設定」,確保物件出生時帶著必要的資料。self
幫你把每個物件區分開,不會混在一起。學到這邊肯定要分享我在大學時期學這邊的心!路!歷!程~
我還記得自己第一次接觸物件導向的時候,完全傻眼。
看到 class
、__init__
、self
,心裡只想:我還是乖乖的寫函式就好…….
以前我都是用函式做事情,像 ATM 模擬器,每個帳戶都要自己傳餘額,
弄得我真的眼花撩亂。
可是當我真的開始寫第一個類別、建立物件、呼叫方法,看到每個帳戶、每個學生都「自己記得自己的資料」時,那一刻我才懂:
「物件不是抽象的東西,它就像程式裡的小生命,
每個物件都有自己的名字、自己的狀態,還會自己做事。」
當然,一開始我也踩過雷,搞錯 self
、忘記打底線,
不會呼叫(或是亂呼叫哈哈哈)!!
但慢慢地,我開始能把生活裡的東西想成「類別」,再把它們變成物件。
回頭看,我覺得學物件導向就像把一堆亂七八糟的資料整理成小宇宙,
每個小宇宙都有自己的規則,也能互相作用。
希望你們也能像我一樣,慢慢從「霧裡看花」到「上手」,
享受物件導向帶來的方便和樂趣!!(而且看起來也比較整齊一點)
明天,我們會進一步學習:
讀者也可以自己練習看看今天的範例~明天也會更上手一點!
那麼,今天辛苦啦!!我們明天見!!