Python 例外處理實戰:打造不怕輸入錯誤的飲料店 POS 點餐系統
顧客可能輸入錯誤的商品代碼、把「兩杯」當成數字、輸入負數杯數,甚至付款不足。真正可靠的程式,不是永遠不會遇到錯誤,而是能辨識可預期的錯誤,給出提示並讓使用者重新操作。本篇從生活情境出發,整合字典、迴圈、函式、類別、例外處理,完成可在終端機執行的飲料店 POS。
一、情境與學習目標
店裡販售紅茶(30 元)、珍珠奶茶(50 元)、綠茶(35 元)。顧客可重複選購商品、輸入杯數,輸入 0 結帳;系統列出明細、計算總額、收款及找零。
完成後,你應能回答:哪些錯誤應使用 try/except?哪些情況要用 if 驗證?為什麼把輸入流程與訂單資料分開設計?
二、先看系統流程
三、第一步:用字典建立菜單
MENU = {"1": ("紅茶", 30),
"2": ("珍珠奶茶", 50),
"3": ("綠茶", 35)}商品代碼使用字串,商品資料以 (名稱, 單價) 表示。透過 MENU[code] 可以找到對應商品;如果代碼不存在,應該提供清楚的錯誤訊息,而不是讓程式直接崩潰。
四、第二步:先處理最常見的輸入錯誤
def read_quantity():
while True:
try:
quantity = int(input("數量(杯):"))
if quantity <= 0:
raise ValueError("數量必須大於 0")
return quantity
except ValueError as error:
print(f"輸入錯誤:{error},請重新輸入。")int() 遇到「兩杯」會產生 ValueError;數量為 0 或負數則是我們定義的商業規則,使用 raise ValueError(...) 主動拒絕。兩者都由同一個 except 處理,再用迴圈重新詢問。
五、第三步:用類別管理訂單
class Order:
def __init__(self):
self.items = []
def add_item(self, code, quantity):
if code not in MENU:
raise KeyError("找不到這個商品代碼")
if quantity <= 0:
raise ValueError("數量必須大於 0")
name, price = MENU[code]
self.items.append((name, price, quantity))
def total(self):
return sum(price * qty for _, price, qty in self.items)Order 負責保存訂單和計算金額;add_item() 再次檢查資料,避免其他程式繞過輸入介面時加入不合理的商品。這就是封裝與例外處理的結合。
六、第四步:結帳時處理付款不足
def checkout(order):
total = order.total()
while True:
try:
paid = int(input(f"應收 {total} 元,請輸入實收金額:"))
if paid < total:
raise ValueError("實收金額不足")
except ValueError as error:
print(f"付款失敗:{error},請重新輸入。")
else:
print(f"找零:{paid - total}元")
print("交易完成,謝謝光臨!")
return這裡的 else 只有在 try 沒有產生例外時才執行。實收金額不足時不會結帳,而是要求重新輸入。這是課堂示範的現金收款模型,尚未包含折扣、發票或交易紀錄。
七、完整可執行程式
將以下程式存成 drink_pos.py,在終端機輸入 python drink_pos.py 執行。不需要額外安裝套件。
"""飲料店 POS:以教學為目的的命令列範例。"""
MENU = {"1": ("紅茶", 30), "2": ("珍珠奶茶", 50), "3": ("綠茶", 35)}
class Order:
def __init__(self):
self.items = []
def add_item(self, code, quantity):
if code not in MENU:
raise KeyError("找不到這個商品代碼")
if quantity <= 0:
raise ValueError("數量必須大於 0")
name, price = MENU[code]
self.items.append((name, price, quantity))
def total(self):
return sum(price * qty for _, price, qty in self.items)
def show_receipt(self):
print("\n=== 訂單明細 ===")
for name, price, qty in self.items:
print(f"{name} {qty}杯 × {price}元 = {price * qty}元")
print(f"合計:{self.total()}元")
def read_quantity():
while True:
try:
quantity = int(input("數量(杯):"))
if quantity <= 0:
raise ValueError("數量必須大於 0")
return quantity
except ValueError as error:
print(f"輸入錯誤:{error},請重新輸入。")
def checkout(order):
total = order.total()
while True:
try:
paid = int(input(f"應收 {total} 元,請輸入實收金額:"))
if paid < total:
raise ValueError("實收金額不足")
except ValueError as error:
print(f"付款失敗:{error},請重新輸入。")
else:
print(f"找零:{paid - total}元")
print("交易完成,謝謝光臨!")
return
def main():
order = Order()
print("=== Python 飲料店 POS ===")
while True:
print("\n菜單:")
for code, (name, price) in MENU.items():
print(f"{code}. {name} {price}元")
code = input("商品代碼(0 結帳):").strip()
if code == "0":
if not order.items:
print("目前沒有商品,結束程式。")
return
break
try:
if code not in MENU:
raise KeyError("沒有這個商品代碼")
qty = read_quantity()
order.add_item(code, qty)
except KeyError as error:
print(f"選購失敗:{error.args[0]},請重新選擇。")
else:
print("商品已加入訂單。")
order.show_receipt()
checkout(order)
if __name__ == "__main__":
main()
八、執行測試:讓錯誤真的發生
=== Python 飲料店 POS ===
菜單:
1. 紅茶 30元
2. 珍珠奶茶 50元
3. 綠茶 35元
商品代碼(0 結帳):9
選購失敗:沒有這個商品代碼,請重新選擇。
商品代碼(0 結帳):2
數量(杯):兩杯
輸入錯誤:invalid literal for int() with base 10: '兩杯',請重新輸入。
數量(杯):-1
輸入錯誤:數量必須大於 0,請重新輸入。
數量(杯):2
商品已加入訂單。
商品代碼(0 結帳):0
=== 訂單明細 ===
珍珠奶茶 2杯 × 50元 = 100元
合計:100元
應收 100 元,請輸入實收金額:50
付款失敗:實收金額不足,請重新輸入。
應收 100 元,請輸入實收金額:200
找零:100元
交易完成,謝謝光臨!上方為示意互動紀錄,實際終端機畫面會依輸入而異。
九、程式中的例外處理與條件判斷
| 情境 | 處理方式 | 原因 |
|---|---|---|
| 輸入「兩杯」 | except ValueError | int() 無法轉換 |
| 輸入 -1 杯 | if + raise ValueError | 違反購買數量規則 |
| 商品代碼 9 | raise KeyError + except | 菜單沒有此商品 |
| 付款不足 | if + raise ValueError | 違反付款規則 |
| 正常付款 | else | 沒有發生例外才完成交易 |
except 處理。程式設計時,先以條件判斷描述正常的業務規則,再用例外表示無法完成操作的情況。也不要使用 except: pass 把問題全部隱藏。十、三階段 AI 協作實習
No-AI|獨立理解
不使用 AI,畫出點餐流程,指出至少三個可能發生錯誤的地方,並說明 while、try、except 各自負責什麼。
AI Pair|共同改善
請 AI 協助新增「同商品累計杯數」及「輸入 q 取消交易」功能。學生必須自行測試空訂單、非法代碼與取消操作。
Challenge AI|驗證 AI
要求 AI 將 POS 擴充成「庫存有限」的版本。測試庫存不足、輸入 0 杯、超額付款與連續輸入錯誤,並檢查是否發生先扣庫存、後來卻結帳失敗的資料不一致問題。
十一、延伸挑戰與教學反思
本範例刻意保持精簡,讓學生先理解錯誤發生時如何恢復。下一步可增加商品庫存、訂單編號、檔案儲存、GUI 或 Django 網頁介面。正式 POS 還需要考慮金額精度、資料持久化、交易一致性與權限管理。
AI 可以快速寫出 try/except,但真正的程式設計能力,是判斷什麼情況應重試、拒絕、取消或回復資料。當學生能清楚回答這些問題,就不只是會寫語法,而是開始學會設計可靠的系統。
Python 程式實習|生活化教學 × 物件導向 × 例外處理 × AI 協作
沒有留言:
張貼留言